#一 hello django
-
创建虚拟环境**(virtualenv 和virtualenvwrapper)
1.1, virtualenv的概述
virtualenv是用来创建Python的虚拟环境的库,虚拟环境能够独立于真实环境存在,并且可以同时有多个互相独立的Python虚拟环境,每个虚拟环境都可以营造一个干净的开发环境,对于项目的依赖、版本的控制有着非常重要的作用。 虚拟环境有什么意义? 如果我们要同时开发多个应用程序,应用A需要Django1.11,而应用B需要Django1.8怎么办? 这种情况下,每个应用可能需要各自拥有一套“独立”的Python运行环境。 virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
1.2, virtualenv 的安装和使用
1.2.1,安装和创建virtualenv
a,安装虚拟环境:安装virtualenv跟安装一般的Python库是一样的操作,直接使用pip命令就行了:
pip3 install virtualenv
b,创建虚拟环境:安装完成之后就可以使用virtualenv的命令来创建虚拟环境了,
首先需要进入需要创建虚拟环境的文件夹,比如F盘的envs文件夹,
然后使用以下命令创建一个虚拟环境,python版本的路径是可选的:
virtualenv 虚拟环境名称 [-p python版本的路径] virtualenv env1 --python==python3
如:virtualenv env1
1.2.2,启动虚拟环境:
source env1/bin/activate
进入虚拟环境后:
使用pip安装numpy模块
创建test.py文件,并在文件中使用numpy模块
在cmd命令窗口使用python test.py执行文件
1.2.3,退出虚拟环境(进入真实系统环境):
deactivate
(如果报错则使用:env1\Scripts\deactivate)
退出虚拟环境后再执行test.py:
在cmd命令窗口使用python test.py执行文件
1.3, virtualenvwrapper 的安装和使用(virtualenvwrapper是virtualenv的包装版,以后用这个,更加方便)
Windows: pip install virtualenvwrapper-win
(Linux:pip install virtualenvwrapper)
创建:mkvirtualenv 虚拟环境名称 -p python的路径
删除:rmvirtualenv 虚拟环境名称
(注意:创建的虚拟环境放在用户目录下的Envs中)
进入:workon 虚拟环境名称
退出:deactivate
ubuntu 安装虚拟环境:
1、安装 virtualenvwrapper
pip install virtualenvwrapper
2、创建目录存放虚拟环境
mkdir ~/.virtualenvs
3、在.bashrc中末尾添加
export WORKON_HOME=~/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
4、运行 source ~/.bashrc
1.4, pip常用命令
pip install xxx:安装xxx依赖包
pip list:查看所有依赖包
pip freeze:查看新安装的包
pip uninstall xxx :卸载xxx包
课堂练习:分别为python2.7和python3.6创建虚拟环境 。
-
安装django
安装Django: pip install django(也可指定某一版本 pip install django==1.11)
测试Django是否安装成功
进入python环境
import django
django.get_version()
课堂练习:在上一步创建的虚拟环境中分别安装django。 -
创建一个Django项目
进入到指定要存放项目的目录,执行 django-admin startproject xxx 来创建一个名字为xxx的工程
查看默认目录结构
manage.py:是Django用于管理本项目的命令行工具,之后进行站点运行,数据库自动生成等都是通过本文件完成。 HelloDjango/__init__.py告诉python该目录是一个python包,暂无内容,后期一些工具的初始化可能会用到 HelloDjango/settings.py Django项目的配置文件,默认状态其中定义了本项目引用的组件,项目名,数据库,静态资源等。 HelloDjango/urls.py 维护项目的URL路由映射,即定义当客户端访问时由哪个模块进行响应。 HelloDjango/wsgi.py 定义WSGI的接口信息,主要用于服务器集成,通常本文件生成后无需改动。
-
测试服务器的启动
python manage.py runserver [ip:port]
可以直接进行服务运行 默认执行起来的端口是8000 也可以自己指定ip和端口: 监听机器所有可用 ip (电脑可能有多个内网ip或多个外网ip):python manage.py runserver 0.0.0.0:8000 如果是外网或者局域网电脑上可以用其它电脑查看开发服务器,访问对应的 ip加端口,比如 10.36.132.2:8000 浏览器访问:http://localhost:8000 可以看到服务器启动成功
-
数据迁移
迁移的概念:就是将模型映射到数据库的过程生成迁移:python manage.py makemigrations
执行迁移:python manage.py migrate
-
创建应用
python manage.py startapp XXX
创建名称为XXX的应用
使用应用前需要将应用配置到项目中,在settings.py中将应用加入到INSTALLED_APPS选项中应用目录介绍
__init__.py:其中暂无内容,使得app成为一个包 admin.py:管理站点模型的声明文件,默认为空 apps.py:应用信息定义文件,在其中生成了AppConfig,该类用于定义应用名等数据 models.py:添加模型层数据类文件 views.py:定义URL相应函数(路由规则) migrations包:自动生成,生成迁移文件的 tests.py:测试代码文件
-
基本视图
首先我们在views.py中建立一个路由响应函数
from django.http import HttpResponsedef welcome(request):
return HttpResponse(‘HelloDjango’)接着我们在urls中进行注册
from App import views
url(r’^welcome/’,views.welcome)基于模块化的设计,我们通常会在每个app中定义自己的urls
在项目的urls中将app的urls包含进来
from django.conf.urls import include
url(r’^welcome/’,include(‘App.urls’))课堂练习:新建一个应用showtime,每次刷新页面显示不同的时间。
-
基本模板
模板实际上就是我们用HTML写好的页面创建模板文件夹templates, 在模板文件夹中创建模板文件
在views中去加载渲染模板, 使用render函数: return render(request,‘xxx’)
课堂练习:在上一个课堂练习中,使用template显示页面内容。
-
定义模型
在models.py 中引入models
from django.db import models创建自己的模型类,但切记要继承自 models.Model
案例驱动,使用模型定义班级,并在模板上显示班级列表
班级: table : grades columns: 班级名称 - name 成立时间 - date 女生个数 - girlnum 男生个数 - boynum 是否删除 - is_delete
-
Admin 后台管理
在admin.py中将model加入后台管理:
admin.site.register(Grade)
创建超级用户:python manage.py createsuperuser
访问admin后台:http://127.0.0.1:8000/admin/
-
展示班级列表
在views.py文件中编写班级的视图函数:
def grade_list(request):
g_list = Grade.objects.all() # 获取班级所有数据
return render(request, 'grade/grade_list.html', {'g_list': g_list})
模板文件:
{% for grade in g_list %}
{{ grade.sname }}
{% endfor %}
-
配置url
在grade App中新建urls.py文件,输入如下代码:
from django.conf.urls import url
from .views import grade_list
urlpatterns = [
url(r'^grade/$', grade_list),
]
在工程的urls.py文件中添加如下代码:
url(r'^', include('grade.urls')),
练习:
1, 从创建虚拟环境到显示出所有班级再操作至少2次
2,在班级Grade所在项目中创建学生students应用,在模板显示学生列表
学生table:students
columns:
学生姓名 - name
学生性别 - gender
学生年龄 - age
学生简介 - info
是否删除 - is_delete
定义学生类
class Students(models.Model):
name = models.CharField(max_length=20)
gender = models.BooleanField(default=True)
age = models.IntegerField()
info = models.CharField(max_length=20)
is_delete = models.BooleanField(default=False)
#二 url和模板
1. URL
URL地址说明:
[外链图片转存失败(img-g6CGs41y-1568786244368)(G:/web%E6%A1%86%E6%9E%B6/Django/day02/doc/url.png)]
使用url给视图函数传参数
在url配置中将正则部分小括号括起来。比如:
url(r'^time/plus/(\d{1,2})/$', views.hours_ahead)
如果有多个参数则用/隔开,参数需要用分组,比如:
url(r'^time/plus/(\d{1,2})/(\d{1,2})/$', views.hours_ahead),
给参数命名,使用正则分组的别名,比如:
url(r'^time/plus/(?P<time1>\d{1,2})/(?P<time2>\d{1,2})/$', views.hours_ahead)
使用分组别名之后,视图函数的参数必须用分组的别名,但是位置可以不固定。
给url取别名,那么在使用此url的地方可以使用别名。比如:
url(r'^buy/$', views.buy, name='buy'),
url(r'^login/$', views.login, name='login'),
2. 反向解析
在视图函数中,反向解析url:
from django.shortcuts import render, redirect
from django.urls import reverse
def buy(request):
return redirect(reverse('index'))
return redirect(reverse('detail', args=[2]))
return redirect(reverse('detail', kwargs={"id": 2}))
在templates中,使用别名:
{% url 'detail' stu.id %}
使用命名空间:
在工程的urls.py文件中,在include时,可以指定命名空间,更加细化的划分url。比如:
url(r'^App/', include('App.urls', namespace='App')),
指定命令空间后,使用反向解析时需要加上命名空间,比如:
在视图函数中: return redirect(reverse('students:index'))
在templates中: {% url 'students:detail' %}
3. 模板
在Django框架中,模板是可以帮助开发者快速生成呈现给用户页面的工具
模板的设计方式实现了我们MVT中VT的解耦,VT有着N:M的关系,一个V可以调用任意T,一个T可以供任意V使用
模板处理分为两个过程
加载
渲染
模板主要有两个部分
HTML静态代码
动态插入的代码段(挖坑,填坑)
模板中的动态代码段除了做基本的静态填充,还可以实现一些基本的运算,转换和逻辑
模板中的变量: 视图传递给模板的数据,遵守标识符规则
语法: {{ var }}
如果变量不存在,则插入空字符串
python manage.py shell: 进入Python环境, 且会自动导入Django配置,建议使用
>>> python manage.py shell # 进入python环境
>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Nige'})
>>> print (t.render(c))
My name is Nige.
>>> c = template.Context({'name': 'Barry'})
>>> print (t.render(c))
My name is Barry.
模板中的点语法
字典查询
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
'Sally is 43 years old.'
属性或者方法
>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(2017, 5, 2)
>>> d.year
2017
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
'The month is 5 and the year is 2017.'
>>> from django.template import Template, Context
>>> class Person(object):
... def __init__(self, first_name, last_name):
... self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
'Hello, John Smith.'
方法不能有参数。
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
'123 -- 123 -- True'
列表,使用索引,不允许负索引
>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
'Item 2 is carrots.'
模板中的小弊端,调用对象的方法,不能传递参数
模板中的标签
语法 {% tag %}
作用
1. 加载外部传入的变量
2. 在输出中创建文本
3. 控制循环或逻辑
if 语句:
格式:
if单分支
{% if 表达式 %}
语句
{% endif %}
if双分支
{% if 表达式 %}
语句
{% else %}
语句
{% endif %}
if多分支
{% if 表达式 %}
语句
{% elif 表达式 %}
语句
{% else %}
语句
{% endif %}
判断true或false
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
使用and or not,可结合使用,and具有更高优先权。
{% if athlete_list and coach_list %}
<p>Both athletes and coaches are available.</p>
{% endif %}
{% if not athlete_list %}
<p>There are no athletes.</p>
{% endif %}
{% if athlete_list or coach_list %}
<p>There are some athletes or some coaches.</p>
{% endif %}
{% if not athlete_list or coach_list %}
<p>There are no athletes or there are some coaches.</p>
{% endif %}
{% if athlete_list and not coach_list %}
<p>There are some athletes and absolutely no coaches.</p>
{% endif %}
使用多个相同的逻辑操作关键字也是允许的,比如:
{% if athlete_list or coach_list or parent_list or teacher_list %}
使用in和not in,
{% if "bc" in "abcdef" %}
This appears since "bc" is a substring of "abcdef"
{% endif %}
{% if user not in users %}
If users is a list, this will appear if user isn't an element of the list.
{% endif %}
使用is 和is not
{% if somevar is True %}
This appears if and only if somevar is True.
{% endif %}
{% if somevar is not None %}
This appears if somevar isn't None.
{% endif %}
for 语句:
{% for 变量 in 列表 %}
语句1
{% empty %}
语句2
{% endfor %}
当列表为空或不存在时,执行empty之后的语句
{{ forloop.counter }} 表示当前是第几次循环,从1数数
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{%endfor %}
{{ forloop.counter0}}表示当前是第几次循环,从0数数
{{ forloop.revcounter}}表示当前是第几次循环,倒着数数,到1停
{{ forloop.revcounter0}}表示当前第几次循环,倒着数,到0停
{{ forloop.first }} 是否是第一个 布尔值
{% for object in objects %}
{% if forloop.first %}
<li class="first">
{% else %}
<li>
{% endif %}
{{ object }}</li>
{% endfor %}
{{ forloop.last }} 是否是最后一个 布尔值
{% for link in links %}
{{ link }}{% if not forloop.last %} | {% endif %}
{% endfor %}
forloop.parentloop
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}</td>
<td>City #{{ forloop.counter }}</td>
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
注释:
单行注释
{# 被注释掉的内容 #}
多行注释
{% comment %}
内容
{% endcomment %}
过滤器:
{{ var|过滤器 }}
作用:在变量显示前修改
add {{ value|add:2 }}
没有减法过滤器,但是加法里可以加负数
{{ value|add:-2 }}
lower
{{ name|lower }}
upper
{{ my_list|first|upper }}
截断:
{{ bio|truncatechars:30 }}
过滤器可以传递参数,参数需要使用引号引起来
比如join: {{ students|join:'=' }}
默认值:default,格式 {{var|default:value}}
如果变量没有被提供或者为False,空,会使用默认值
根据指定格式转换日期为字符串,处理时间的
就是针对date进行的转换
{{ dateVal | date:'y-m-d' }}
HTML转义
将接收到的数据当成普通字符串处理还是当成HTML代码来渲染的一个问题
渲染成html:{{ code|safe }}
关闭自动转义
{% autoescape off%}
code
{% endautoescape %}
打开自动转义转义
{% autoescape on%}
code
{% endautoescape %}
模板继承
block:挖坑
{% block XXX%}
code
{% endblock %}
extends 继承,写在开头位置
{% extends '父模板路径' %}
include: 加载模板进行渲染
{% include '模板文件' %}
Django中默认集成了后台数据管理页面,通过简单的配置就可以实现模型后台的Web控制台。
管理界面通常是给系统管理员使用的,用来完成数据的输入,删除,查询等工作。
使用以下models来示范admin后台系统的用法。
创建一个项目。用来说明出版社,书籍和作者的关系。
1. 出版社,书籍,作者都有一个首页index.html
2. 在书籍的index.html中有一个"查看所有书籍"的超链接按钮,可以点击进入书籍列表list.html页面
3. 在书籍list.html中显示所有书名,点击书名可以进入书籍详情detail.html
4,在书籍detail.html中可以点击该书的作者和出版社,进入作者的detail.html和出版社的detail.html页面
假定关系:书籍:作者 => n:n (一本书可以由多个作者共同完成, 一个作者也可以创作多本书)
出版社:书籍 => 1:n (一个出版社可以出版多本书, 一本书由一个出版社出版)
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(null=True, blank=True)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
使用admin后台系统之前,需要先创建一个系统管理员,创建管理员之前需先同步数据库。
python manager.py createsuperuser
设置为中文
settings中LANGUAGE_CODE = 'zh-hans'
设置时间,时区
TIME_ZONE='Asia/Shanghai'
添加自己的数据模型
在admin.py中注册
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book))
在admin中给model添加数据。
给模型加上__str__函数,比如给Author模型添加str函数,让author的显示更加友好:
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
希望控制admin中添加model数据时的动作,可以修改相应字段的属性。
比如author的email字段运行添加的时候为空,可以在email字段定义中加上 blank=True(可以空白),
比如book的publication_date添加 blank=True, null=True(可以为null)属性。
修改models属性之后记得及时做数据迁移。
使用verbose_name属性指定字段的别名:
比如给publisher的name字段指定一个中文的别名verbose_name='出版社名称'。
在models的修改页面,默认显示的是models定义的str函数返回的字符串。
通过定义MoldelAdmin来定制model在admin的表现。比如给Author定义AuthorAdmin。
class AuthorAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email')
相应的注册代码也要变化:
admin.site.register(Author, AuthorAdmin)
给Author添加一个搜索框:
search_fields = ('first_name', 'last_name')
给book添加一个过滤器
list_filter = ('publication_date',)
过滤器不光可以作用在日期字段上,还可以作用在boolean类型和外键上。
另一种增加日期过滤的方式:
date_hierarchy = 'publication_date'
字段排序:
ordering = ('-publication_date',)
修改编辑页面显示的字段及显示顺序,默认按照models中字段的定义顺序显示:
fields = ('title', 'authors', 'publisher', 'publication_date')
与fields相反的字段是exclude
exclude = ['publication_date',]
改善多对多关系中对象选择操作,比如给BookAdmin添加如下属性:
filter_horizontal = ('authors',)
filter_horizontal和filter_vertical 选项只适用于多对多关系。
一对多的外键关系,admin使用select box下拉菜单来表示。如不想用select box,可添加如下属性,让原来一次性加载所有publisher的select box变成填写publisher的id:
raw_id_fields = ('publisher',)
让字段分组显示,fieldsets和上面提到的field不能同时出现:
fieldsets = (
('作者', {'fields': ('authors',)}),
('出版商', {'fields': ('publisher',)}),
)
定制list_display字段的显示。比如给Author加一个布尔型gender字段,来表示性别。为了让显示更加人性化:
# 定制显示属性
def showgender(self):
if self.gender:
return '男'
else:
return '女'
list_display = ('first_name', 'last_name', 'email', showgender)
给该函数设置简短描述,让显示更加友好:
showgender.short_description = '性别'
可以将modeladmin的属性简单划分为列表页属性和添加、修改页属性
# 列表页属性
list_display,list_filter,search_fields,list_per_page等
# 添加、修改页属性
fields ,fieldsets, filter_horizontal, raw_id_fields等
Django中默认集成了后台数据管理页面,通过简单的配置就可以实现模型后台的Web控制台。
管理界面通常是给系统管理员使用的,用来完成数据的输入,删除,查询等工作。
使用以下models来示范admin后台系统的用法。
创建一个项目。用来说明出版社,书籍和作者的关系。
1. 出版社,书籍,作者都有一个首页index.html
2. 在书籍的index.html中有一个"查看所有书籍"的超链接按钮,可以点击进入书籍列表list.html页面
3. 在书籍list.html中显示所有书名,点击书名可以进入书籍详情detail.html
4,在书籍detail.html中可以点击该书的作者和出版社,进入作者的detail.html和出版社的detail.html页面
假定关系:书籍:作者 => n:n (一本书可以由多个作者共同完成, 一个作者也可以创作多本书)
出版社:书籍 => 1:n (一个出版社可以出版多本书, 一本书由一个出版社出版)
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(null=True, blank=True)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
使用admin后台系统之前,需要先创建一个系统管理员,创建管理员之前需先同步数据库。
python manager.py createsuperuser
设置为中文
settings中LANGUAGE_CODE = 'zh-hans'
设置时间,时区
TIME_ZONE='Asia/Shanghai'
添加自己的数据模型
在admin.py中注册
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book))
在admin中给model添加数据。
给模型加上__str__函数,比如给Author模型添加str函数,让author的显示更加友好:
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
希望控制admin中添加model数据时的动作,可以修改相应字段的属性。
比如author的email字段运行添加的时候为空,可以在email字段定义中加上 blank=True(可以空白),
比如book的publication_date添加 blank=True, null=True(可以为null)属性。
修改models属性之后记得及时做数据迁移。
使用verbose_name属性指定字段的别名:
比如给publisher的name字段指定一个中文的别名verbose_name='出版社名称'。
在models的修改页面,默认显示的是models定义的str函数返回的字符串。
通过定义MoldelAdmin来定制model在admin的表现。比如给Author定义AuthorAdmin。
class AuthorAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email')
相应的注册代码也要变化:
admin.site.register(Author, AuthorAdmin)
给Author添加一个搜索框:
search_fields = ('first_name', 'last_name')
给book添加一个过滤器
list_filter = ('publication_date',)
过滤器不光可以作用在日期字段上,还可以作用在boolean类型和外键上。
另一种增加日期过滤的方式:
date_hierarchy = 'publication_date'
字段排序:
ordering = ('-publication_date',)
修改编辑页面显示的字段及显示顺序,默认按照models中字段的定义顺序显示:
fields = ('title', 'authors', 'publisher', 'publication_date')
与fields相反的字段是exclude
exclude = ['publication_date',]
改善多对多关系中对象选择操作,比如给BookAdmin添加如下属性:
filter_horizontal = ('authors',)
filter_horizontal和filter_vertical 选项只适用于多对多关系。
一对多的外键关系,admin使用select box下拉菜单来表示。如不想用select box,可添加如下属性,让原来一次性加载所有publisher的select box变成填写publisher的id:
raw_id_fields = ('publisher',)
让字段分组显示,fieldsets和上面提到的field不能同时出现:
fieldsets = (
('作者', {'fields': ('authors',)}),
('出版商', {'fields': ('publisher',)}),
)
定制list_display字段的显示。比如给Author加一个布尔型gender字段,来表示性别。为了让显示更加人性化:
# 定制显示属性
def showgender(self):
if self.gender:
return '男'
else:
return '女'
list_display = ('first_name', 'last_name', 'email', showgender)
给该函数设置简短描述,让显示更加友好:
showgender.short_description = '性别'
可以将modeladmin的属性简单划分为列表页属性和添加、修改页属性
# 列表页属性
list_display,list_filter,search_fields,list_per_page等
# 添加、修改页属性
fields ,fieldsets, filter_horizontal, raw_id_fields等
Django中默认集成了后台数据管理页面,通过简单的配置就可以实现模型后台的Web控制台。
管理界面通常是给系统管理员使用的,用来完成数据的输入,删除,查询等工作。
使用以下models来示范admin后台系统的用法。
创建一个项目。用来说明出版社,书籍和作者的关系。
1. 出版社,书籍,作者都有一个首页index.html
2. 在书籍的index.html中有一个"查看所有书籍"的超链接按钮,可以点击进入书籍列表list.html页面
3. 在书籍list.html中显示所有书名,点击书名可以进入书籍详情detail.html
4,在书籍detail.html中可以点击该书的作者和出版社,进入作者的detail.html和出版社的detail.html页面
假定关系:书籍:作者 => n:n (一本书可以由多个作者共同完成, 一个作者也可以创作多本书)
出版社:书籍 => 1:n (一个出版社可以出版多本书, 一本书由一个出版社出版)
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(null=True, blank=True)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
使用admin后台系统之前,需要先创建一个系统管理员,创建管理员之前需先同步数据库。
python manager.py createsuperuser
设置为中文
settings中LANGUAGE_CODE = 'zh-hans'
设置时间,时区
TIME_ZONE='Asia/Shanghai'
添加自己的数据模型
在admin.py中注册
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book))
在admin中给model添加数据。
给模型加上__str__函数,比如给Author模型添加str函数,让author的显示更加友好:
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
希望控制admin中添加model数据时的动作,可以修改相应字段的属性。
比如author的email字段运行添加的时候为空,可以在email字段定义中加上 blank=True(可以空白),
比如book的publication_date添加 blank=True, null=True(可以为null)属性。
修改models属性之后记得及时做数据迁移。
使用verbose_name属性指定字段的别名:
比如给publisher的name字段指定一个中文的别名verbose_name='出版社名称'。
在models的修改页面,默认显示的是models定义的str函数返回的字符串。
通过定义MoldelAdmin来定制model在admin的表现。比如给Author定义AuthorAdmin。
class AuthorAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email')
相应的注册代码也要变化:
admin.site.register(Author, AuthorAdmin)
给Author添加一个搜索框:
search_fields = ('first_name', 'last_name')
给book添加一个过滤器
list_filter = ('publication_date',)
过滤器不光可以作用在日期字段上,还可以作用在boolean类型和外键上。
另一种增加日期过滤的方式:
date_hierarchy = 'publication_date'
字段排序:
ordering = ('-publication_date',)
修改编辑页面显示的字段及显示顺序,默认按照models中字段的定义顺序显示:
fields = ('title', 'authors', 'publisher', 'publication_date')
与fields相反的字段是exclude
exclude = ['publication_date',]
改善多对多关系中对象选择操作,比如给BookAdmin添加如下属性:
filter_horizontal = ('authors',)
filter_horizontal和filter_vertical 选项只适用于多对多关系。
一对多的外键关系,admin使用select box下拉菜单来表示。如不想用select box,可添加如下属性,让原来一次性加载所有publisher的select box变成填写publisher的id:
raw_id_fields = ('publisher',)
让字段分组显示,fieldsets和上面提到的field不能同时出现:
fieldsets = (
('作者', {'fields': ('authors',)}),
('出版商', {'fields': ('publisher',)}),
)
定制list_display字段的显示。比如给Author加一个布尔型gender字段,来表示性别。为了让显示更加人性化:
# 定制显示属性
def showgender(self):
if self.gender:
return '男'
else:
return '女'
list_display = ('first_name', 'last_name', 'email', showgender)
给该函数设置简短描述,让显示更加友好:
showgender.short_description = '性别'
可以将modeladmin的属性简单划分为列表页属性和添加、修改页属性
# 列表页属性
list_display,list_filter,search_fields,list_per_page等
# 添加、修改页属性
fields ,fieldsets, filter_horizontal, raw_id_fields等
Django中默认集成了后台数据管理页面,通过简单的配置就可以实现模型后台的Web控制台。
管理界面通常是给系统管理员使用的,用来完成数据的输入,删除,查询等工作。
使用以下models来示范admin后台系统的用法。
创建一个项目。用来说明出版社,书籍和作者的关系。
1. 出版社,书籍,作者都有一个首页index.html
2. 在书籍的index.html中有一个"查看所有书籍"的超链接按钮,可以点击进入书籍列表list.html页面
3. 在书籍list.html中显示所有书名,点击书名可以进入书籍详情detail.html
4,在书籍detail.html中可以点击该书的作者和出版社,进入作者的detail.html和出版社的detail.html页面
假定关系:书籍:作者 => n:n (一本书可以由多个作者共同完成, 一个作者也可以创作多本书)
出版社:书籍 => 1:n (一个出版社可以出版多本书, 一本书由一个出版社出版)
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(null=True, blank=True)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
使用admin后台系统之前,需要先创建一个系统管理员,创建管理员之前需先同步数据库。
python manager.py createsuperuser
设置为中文
settings中LANGUAGE_CODE = 'zh-hans'
设置时间,时区
TIME_ZONE='Asia/Shanghai'
添加自己的数据模型
在admin.py中注册
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book))
在admin中给model添加数据。
给模型加上__str__函数,比如给Author模型添加str函数,让author的显示更加友好:
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
希望控制admin中添加model数据时的动作,可以修改相应字段的属性。
比如author的email字段运行添加的时候为空,可以在email字段定义中加上 blank=True(可以空白),
比如book的publication_date添加 blank=True, null=True(可以为null)属性。
修改models属性之后记得及时做数据迁移。
使用verbose_name属性指定字段的别名:
比如给publisher的name字段指定一个中文的别名verbose_name='出版社名称'。
在models的修改页面,默认显示的是models定义的str函数返回的字符串。
通过定义MoldelAdmin来定制model在admin的表现。比如给Author定义AuthorAdmin。
class AuthorAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email')
相应的注册代码也要变化:
admin.site.register(Author, AuthorAdmin)
给Author添加一个搜索框:
search_fields = ('first_name', 'last_name')
给book添加一个过滤器
list_filter = ('publication_date',)
过滤器不光可以作用在日期字段上,还可以作用在boolean类型和外键上。
另一种增加日期过滤的方式:
date_hierarchy = 'publication_date'
字段排序:
ordering = ('-publication_date',)
修改编辑页面显示的字段及显示顺序,默认按照models中字段的定义顺序显示:
fields = ('title', 'authors', 'publisher', 'publication_date')
与fields相反的字段是exclude
exclude = ['publication_date',]
改善多对多关系中对象选择操作,比如给BookAdmin添加如下属性:
filter_horizontal = ('authors',)
filter_horizontal和filter_vertical 选项只适用于多对多关系。
一对多的外键关系,admin使用select box下拉菜单来表示。如不想用select box,可添加如下属性,让原来一次性加载所有publisher的select box变成填写publisher的id:
raw_id_fields = ('publisher',)
让字段分组显示,fieldsets和上面提到的field不能同时出现:
fieldsets = (
('作者', {'fields': ('authors',)}),
('出版商', {'fields': ('publisher',)}),
)
定制list_display字段的显示。比如给Author加一个布尔型gender字段,来表示性别。为了让显示更加人性化:
# 定制显示属性
def showgender(self):
if self.gender:
return '男'
else:
return '女'
list_display = ('first_name', 'last_name', 'email', showgender)
给该函数设置简短描述,让显示更加友好:
showgender.short_description = '性别'
可以将modeladmin的属性简单划分为列表页属性和添加、修改页属性
# 列表页属性
list_display,list_filter,search_fields,list_per_page等
# 添加、修改页属性
fields ,fieldsets, filter_horizontal, raw_id_fields等
三 mysql&admin后台系统
1. mysql的使用
1,在windows安装mysql数据库, 安装方法参考《mysql安装.pdf》,记住安装过程中的设置的mysql数据库用户名和密码;
2,用管理员权限打开cmd.exe, 在cmd窗口输入命令:net start mysql57 来启动mysql;
3,安装Navicat;
4,打开navicat, 点击'连接'来创建与mysql的连接, 然后创建数据库test;
5,在Django中配置和使用mysql数据库
使用mysql数据库,settings中配置如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
安装mysql依赖包:
pip install -i https://pypi.douban.com/simple mysqlclient
如安装该包出错。下载新包:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient
2. django admin后台系统
Django中默认集成了后台数据管理页面,通过简单的配置就可以实现模型后台的Web控制台。
管理界面通常是给系统管理员使用的,用来完成数据的输入,删除,查询等工作。
使用以下models来示范admin后台系统的用法。
创建一个项目。用来说明出版社,书籍和作者的关系。
1. 出版社,书籍,作者都有一个首页index.html
2. 在书籍的index.html中有一个"查看所有书籍"的超链接按钮,可以点击进入书籍列表list.html页面
3. 在书籍list.html中显示所有书名,点击书名可以进入书籍详情detail.html
4,在书籍detail.html中可以点击该书的作者和出版社,进入作者的detail.html和出版社的detail.html页面
假定关系:书籍:作者 => n:n (一本书可以由多个作者共同完成, 一个作者也可以创作多本书)
出版社:书籍 => 1:n (一个出版社可以出版多本书, 一本书由一个出版社出版)
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(null=True, blank=True)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
使用admin后台系统之前,需要先创建一个系统管理员,创建管理员之前需先同步数据库。
python manager.py createsuperuser
设置为中文
settings中LANGUAGE_CODE = 'zh-hans'
设置时间,时区
TIME_ZONE='Asia/Shanghai'
添加自己的数据模型
在admin.py中注册
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book))
在admin中给model添加数据。
给模型加上__str__函数,比如给Author模型添加str函数,让author的显示更加友好:
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
希望控制admin中添加model数据时的动作,可以修改相应字段的属性。
比如author的email字段运行添加的时候为空,可以在email字段定义中加上 blank=True(可以空白),
比如book的publication_date添加 blank=True, null=True(可以为null)属性。
修改models属性之后记得及时做数据迁移。
使用verbose_name属性指定字段的别名:
比如给publisher的name字段指定一个中文的别名verbose_name='出版社名称'。
在models的修改页面,默认显示的是models定义的str函数返回的字符串。
通过定义MoldelAdmin来定制model在admin的表现。比如给Author定义AuthorAdmin。
class AuthorAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email')
相应的注册代码也要变化:
admin.site.register(Author, AuthorAdmin)
给Author添加一个搜索框:
search_fields = ('first_name', 'last_name')
给book添加一个过滤器
list_filter = ('publication_date',)
过滤器不光可以作用在日期字段上,还可以作用在boolean类型和外键上。
另一种增加日期过滤的方式:
date_hierarchy = 'publication_date'
字段排序:
ordering = ('-publication_date',)
修改编辑页面显示的字段及显示顺序,默认按照models中字段的定义顺序显示:
fields = ('title', 'authors', 'publisher', 'publication_date')
与fields相反的字段是exclude
exclude = ['publication_date',]
改善多对多关系中对象选择操作,比如给BookAdmin添加如下属性:
filter_horizontal = ('authors',)
filter_horizontal和filter_vertical 选项只适用于多对多关系。
一对多的外键关系,admin使用select box下拉菜单来表示。如不想用select box,可添加如下属性,让原来一次性加载所有publisher的select box变成填写publisher的id:
raw_id_fields = ('publisher',)
让字段分组显示,fieldsets和上面提到的field不能同时出现:
fieldsets = (
('作者', {'fields': ('authors',)}),
('出版商', {'fields': ('publisher',)}),
)
定制list_display字段的显示。比如给Author加一个布尔型gender字段,来表示性别。为了让显示更加人性化:
# 定制显示属性
def showgender(self):
if self.gender:
return '男'
else:
return '女'
list_display = ('first_name', 'last_name', 'email', showgender)
给该函数设置简短描述,让显示更加友好:
showgender.short_description = '性别'
可以将modeladmin的属性简单划分为列表页属性和添加、修改页属性
# 列表页属性
list_display,list_filter,search_fields,list_per_page等
# 添加、修改页属性
fields ,fieldsets, filter_horizontal, raw_id_fields等
四 models模型
1. models 定义属性
概述
django根据属性的类型确定以下信息
·当前选择的数据库支持字段的类型
·渲染管理表单时使用的默认html控件
·在管理站点最低限度的验证
django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
属性命名限制
·遵循标识符规则
·由于django的查询方式,不允许使用连续的下划线
定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
使用方式
·导入from django.db import models
·通过models.Field创建字段类型的对象,赋值给属性
逻辑删除
对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
常用字段类型:
·AutoField
·一个根据实际ID自动增长的IntegerField,通常不指定, 如果不指定,主键字段将自动添加到模型中
·CharField(max_length=字符长度)
·字符串,默认的表单样式是 TextInput
·TextField
·大文本字段,一般超过4000使用,默认的表单控件是Textarea
·IntegerField
·整数
·DecimalField(max_digits=None, decimal_places=None)
·使用python的Decimal实例表示的十进制浮点数
·参数说明
·DecimalField.max_digits
·位数总数
·DecimalField.decimal_places
·小数点后的数字位数
·FloatField
·用Python的float实例来表示的浮点数
·BooleanField
·true/false 字段,此字段的默认表单控制是CheckboxInput
·NullBooleanField
·支持null、true、false三种值
·DateField([auto_now=False, auto_now_add=False])
·使用Python的datetime.date实例表示的日期
·参数说明
·DateField.auto_now
·每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
·DateField.auto_now_add
·当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
注意:auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
·TimeField
·使用Python的datetime.time实例表示的时间,参数同DateField
·DateTimeField
·使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
·FileField
·一个上传文件的字段
·ImageField
·继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
2. 常用字段选项
常用字段选项(通过字段选项,可以实现对字段的约束):
1、 null=True
数据库中字段是否可以为空
2、 blank=True
django的 Admin 中添加数据时是否可允许空值
一般null=True & blank=True 搭配着用,出现null=True就用上blank=True
3、 primary_key = True
主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、 auto_now 和 auto_now_add
auto_now 自动创建---无论添加或修改,都是当前操作的时间
auto_now_add 自动创建---永远是创建时的时间
5、 choices (后台admin下拉菜单)
USER_TYPE_LIST = (
(1, '超级用户'),
(2, '普通用户'),
)
user_type = models.IntegerField(choices=USER_TYPE_LIST,default=1,verbose_name='用户类型')
6、 max_length 最大长度
7、 default 默认值
8、 verbose_name Admin(后台显示的名称)中字段的显示名称
9、 name|db_column 数据库中的字段名称
10、unique=True 不允许重复
11、db_index = True 数据库索引,例如:如果你想通过name查询的更快的话,给他设置为索引即可
12、editable=True 在Admin里是否可编辑,不可编辑则不显示
3. models基本操作
一般的数据库操作流程:
1. 创建数据库,设计表结构和字段
2. 连接Mysql数据库,并编写数据访问层代码
3. 业务逻辑层去调用数据访问层执行数据库操作
Django通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Django自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。只要会写Model就可以了。
django使用关系对象映射(Object Relational Mapping,简称ORM)框架去操控数据库。
ORM(Object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
可以简单理解为翻译机。
增删改查
models基本操作
增:
1)创建对象实例,然后调用save方法:
obj = Author(first_name='zhang', last_name='san')
obj.save()
2)使用create方法
Author.objects.create(first_name='li', last_name='si')
删:
使用queryset的delete方法:
# 删除指定条件的数据
Author.objects.filter(first_name='zhang').delete()
# 删除所有数据
Author.objects.all().delete()
注意: objects不能直接调用delete方法。
使用模型对象的delete方法:
obj = Author.objects.get(id=5)
obj.delete()
改:
Author.objects.filter(last_name='dfdf').update(last_name='san')
模型没有定义update方法,直接给字段赋值,并调用save,能实现update的功能,比如:
>>> obj = Author.objects.get(id=3)
>>> obj.first_name = 'zhang'
>>> obj.save()
save更新时会更新所有字段。如果只想更新某个字段,减少数据库操作,可以这么做:
obj.first_name = 'li'
obj.save(update_fields=['first_name'])
注意:更新操作不能更新关联表的属性,比如下面的语句是不起作用的。
Author.objects.update(book__title='b')
查:
获取单条数据:Author.objects.get(id=123)
get():返回一个满足条件的对象
如果没有找到符合条件的对象,会引发 模型类.DoesNotExist异常
如果找到多个,会引发 模型类.MultipleObjectsReturned 异常
first():返回查询集中的第一个对象
last():返回查询集中的最后一个对象
count():返回当前查询集中的对象个数
exists():判断查询集中是否有数据,如果有数据返回True没有反之
Author.objects.all() # 获取全部
Author.objects.filter(name='seven') # 获取指定条件的数据
Author.objects.all().values('password')#获取指定列的值,可以传多个参数!返回列表。
进阶操作:
# 获取个数
Author.objects.filter(name='seven').count()
Author.objects.filter(id__gt=1) # 获取id大于1的值
Author.objects.filter(id__lt=10) # 获取id小于10的值
Author.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
# Author.objects.filter(id__in=[11, 22, 33]) # 获取id在11、22、33中的数据
Author.objects.exclude(id__in=[11, 22, 33]) # not in
Author.objects.filter(name__contains="ven") # contains(和数据中like语法相同)
Author.objects.filter(name__icontains="ven") # icontains大小写不敏感
Author.objects.filter(id__range=[1, 2]) # 范围bettwen and
# startswith,istartswith, endswith, iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的
Author.objects.filter(name='seven').order_by('id') # asc正序
Author.objects.filter(name='seven').order_by('-id') # desc反序
Author.objects.all()[10:20] #取所有数据的10条到20条,分页的时候用的到,下标从0开始,不能为负数
# 聚合
使用aggregate()函数返回聚合函数的值
Avg:平均值
Count:数量
Max:最大
Min:最小
Sum:求和
from django.db.models import Count, Min, Max, Sum
Author.objects.aggregate(Max('age'))
# 注解
obj = Author.objects.annotate(num_books=Count('book'))
obj[0].num_books
day 05 models进阶
1.models基本操作
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
对于ORM框架里:
我们写的类表示数据库的表
如果根据这个类创建的对象是数据库表里的一行数据
那么对象.属性(对象.id 对象.value)就是每一行里的数据
models基本操作
增:
1)创建对象实例,然后调用save方法:
obj = Author(first_name='zhang', last_name='san')
obj.save()
2)使用create方法
Author.objects.create(first_name='li', last_name='si')
3)使用get_or_create方法,可以防止重复
Author.objects.get_or_create(first_name='zhang', last_name='san')
删:
使用Queryset的delete方法:
# 删除指定条件的数据
Author.objects.filter(first_name='zhang').delete()
# 删除所有数据
Author.objects.all().delete()
注意: objects不能直接调用delete方法。
使用模型对象的delete方法:
obj = Author.objects.get(id=5)
obj.delete()
改:
Author.objects.filter(last_name='dfdf').update(last_name='san')
模型没有定义update方法,直接给字段赋值,并调用save,能实现update的功能,比如:
>>> obj = Author.objects.get(id=3)
>>> obj.first_name = 'zhang'
>>> obj.save()
save更新时会更新所有字段。如果只想更新某个字段,减少数据库操作,可以这么做:
obj.first_name = 'li'
obj.save(update_fields=['first_name'])
注意:更新操作不能更新关联表的属性,比如下面的语句是不起作用的。
Author.objects.update(book__title='b')
查:
获取单条数据:Author.objects.get(id=123)
get():返回一个满足条件的对象
如果没有找到符合条件的对象,会引发 模型类.DoesNotExist异常
如果找到多个,会引发 模型类.MultipleObjectsReturned 异常
first():返回查询集中的第一个对象
last():返回查询集中的最后一个对象
count():返回当前查询集中的对象个数
exists():判断查询集中是否有数据,如果有数据返回True没有反之
Author.objects.all() # 获取全部
Author.objects.filter(name='seven') # 获取指定条件的数据
Author.objects.all().values('password') # 获取指定列的值,可以传多个参数!返回包含字典的列表(保存了字段名和对应的值)
Author.objects.all().values_list('password') # 获取指定列的值,可以传多个参数!返回包含元组列表(只保存值)
进阶操作:
# 获取个数
Author.objects.filter(name='seven').count()
#select count(*) from Author where name='seven'
Author.objects.filter(id__gt=1) # 获取id大于1的值
Author.objects.filter(id__gte=1) # 获取id大于或等于1的值
#select * from Author where id>1
Author.objects.filter(id__lt=10) # 获取id小于10的值
Author.objects.filter(id__lte=10) # 获取id小于等于或d10的值
#select * from Author where id<10
Author.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
#select * from Author where id<10 and id>1
Author.objects.filter(id__in=[11, 22, 33]) # 获取id在11、22、33中的数据
#select * from Author where id in (11,22,33)
Author.objects.exclude(id__in=[11, 22, 33]) # not in
#select * from Author where id not in (11,22,33)
Author.objects.filter(name__contains="ven") # contains(和数据中like语法相同)
#select * from Author where name like '%ven%'
#select * from Author where name like '%v\%n%'
Author.objects.filter(name__icontains="ven") # icontains大小写不敏感
Author.objects.filter(name__regex="^ven") # 正则匹配
Author.objects.filter(name__iregex="^ven") # 正则匹配,忽略大小写
Author.objects.filter(id__range=[1, 2]) # 范围bettwen and
# startswith,istartswith, endswith, iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的
Author.objects.filter(name='seven').order_by('id') # asc正序
Author.objects.filter(name='seven').order_by('-id') # desc反序
Author.objects.all()[10:20] #切片,取所有数据的10条到20条,分页的时候用的到,下标从0开始,不能为负数
# 聚合
使用aggregate()函数返回聚合函数的值
Avg:平均值
Count:数量
Max:最大
Min:最小
Sum:求和
from django.db.models import Count, Min, Max, Sum
Author.objects.aggregate(Max('age'))
# 注解
obj = Author.objects.annotate(num_books=Count('book'))
obj[0].num_books
2. 模块关联关系
关系
·分类
·ForeignKey:一对多,将字段定义在多的端中
·ManyToManyField:多对多,将字段定义在两端中
·OneToOneField:一对一,将字段定义在任意一端中
一对多关系,举例说明(一对一, 多对多类似):
一个班级可以有多个学生, 一个学生只能属于一个班级
class Grade(models.Model):
name = models.CharField(max_length=20)
class Student(models.Model):
name = models.CharField(max_length=20)
grade = models.ForeignKey(Grade)
对象的使用:
正向(在Student这边,有grade属性的这一边):
获取学生所在班级(对象): stu.grade
获取学生所在班级的属性: stu.grade.name
反向(在Grade这边):
获取班级的所有学生(获取Manager对象):grade.student_set
获取班级的所有学生(获取QuerySet查询集): grade.student_set.all()
filter(),get()等操作中的使用:
正向(在Student这边,有grade属性的这一边):
Student.objects.filter(属性__name=1)
如:Student.objects.filter(grade__name=1)
反向(在Grade这边):
Grade.objects.filter(类名小写__id=7)
如:Grade.objects.filter(student__id=7)
3. Model连表结构
ORM核心知识回顾:
django根据代码中定义的类来自动生成数据库表。
我们写的类表示数据库的表。
根据这个类创建的对象是数据库表里的一行数据。
对象.id 对象.value 是每一行里的数据
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】
多对多:在某表中创建一行数据时,有一个可以多选的下拉框。
例如:创建用户信息,需要为用户指定多个爱好。
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)
例如:有个身份证表,有个person表。每个人只能有一张身份证,一张身份证也只能对应一个人,这就是一对一关系。
1.1 一对多关系,即外键
为什么要用一对多。先来看一个例子。有一个用户信息表,其中有个用户类型字段,存储用户的用户类型。如下:
class UserInfo(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
user_type = models.CharField(max_length=10)
不使用外键时用户类型存储在每一行数据中。如使用外键则只需要存储关联表的id即可,能够节省大量的存储空间。同时使用外键有利于维持数据完整性和一致性。
当然也有缺点,数据库设计变的更复杂了。每次做DELETE 或者UPDATE都必须考虑外键约束。
刚才的例子使用外键的情况:单独定义一个用户类型表:
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
user_type = models.ForeignKey('UserType')
username = models.CharField(max_length=32)
age = models.IntegerField()
我们约定:
正向操作: ForeignKey在UserInfo表里,如果根据UserInfo去操作就是正向操作。
反向操作: ForeignKey不在UserType里,如果根据UserType去操作就是反向操作。
一对多的关系的增删改查:
正向操作:
增
1)创建对象实例,然后调用save方法:
obj = UserInfo(name='li', age=44, user_type_id=2)
obj.save()
2)使用create方法
UserInfo.objects.create(name='li', age=44, user_type_id=2)
3)使用get_or_create方法,可以防止重复
UserInfo.objects.get_or_create(name='li', age=55, user_type_id=2)
4)使用字典。
dic = {'name':'zhangsan','age':18,'user_type_id':3}
UserInfo.objects.create(**dic)
5)通过对象添加
usertype = UserType.objects.get(id=1)
UserInfo.objects.create(name='li', age=55, user_type=usertype)
删
和普通模式一样删除即可。如:
UserInfo.objects.filter(id=1).delete()
改
和普通模式一样修改即可。如:
UserInfo.objects.filter(id=2).update(user_type_id=4)
查
正向查找所有用户类型为钻石用户的用户,使用双下划线:
users = UserInfo.objects.filter(user_type__caption__contains='钻石')
正向获取关联表中的属性可以直接使用点.语法,比如获取users查询集中第一个用户的caption:
users[0].user_type.caption
反向操作:
增 (一般使用正向增即可)
通过usertype来创建userinfo
1) 通过userinfo_set的create方法
#获取usertype实例
ut = UserType.objects.get(id=2)
#创建userinfo
ut.userinfo_set.create(name='smith',age=33)
删
删除操作可以在定义外键关系的时候,通过on_delete参数来配置删除时做的操作。
on_delete参数主要有以下几个可选值:
models.CASCADE 默认值,表示级联删除,即删除UserType时,相关联的
UserInfo也会被删除。
models.PROTECT 保护模式, 阻止级联删除。
models.SET_NULL 置空模式 设为null,null=True参数必须具备
models.SET_DEFAULT 置默认值 设为默认值,default参数必须具备
models.SET() 删除的时候重新动态指向一个实体访问对应元素 ,可传函数
models.DO_NOTHING 什么也不做。
注意: 修改on_delete参数之后需要重新同步数据库,如果使用
python manage.py shell进行models操作,需要退出shell重新进入。
改
和普通模式一样,不会影响级联表。
查
通过usertype对象来查用户类型为1的用户有哪些
obj=UserType.objects.get(id=1)
obj.userinfo_set.all()
可以通过在定义foreignkey时指定related_name来修改默认的userinfo_set,比如指定related_name为info
user_type = models.ForeignKey('UserType',related_name='info')
指定related_name之后,反向查的时候就变成了:
obj.info.all()
获取用户类型为1且用户名为shuaige的用户
obj.info.filter(username='shuaige')
外键关系中,django自动给usertype加了一个叫做userinfo的属性。使用双下划线,可以通过userinfo提供的信息来查usertype (了解)
user_type_obj = UserType.objects.get(userinfo__username='zs')
1.2 多对多关系
针对多对多关系django会自动创建第三张表。也可以通过through参数指定第三张表。
用户和组是典型的多对多关系:
class Group(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class User(models.Model):
name = models.CharField(max_length=64)
password = models.CharField(max_length=64)
groups = models.ManyToManyField(Group)
def __str__(self):
return self.name
操作:
增:
先分别创建user和group, 再使用add关联
u = User(name='aa', password='123')
u.save()
g = UserGroup(name='g5')
g.save()
通过Manager对象使用add()方法
u.groups.add(g) 或 g.user_set.add(u)
删:
和一对多类似,删除user或group会级联删除user_groups表中的关联数据
改:
和一对多类似,只修改当前表
查:
正向:
查询id=2的用户所在的所有组group
u = User.objects.get(id=2)
u.groups.all()
反向:
查询id=1的组中包含的所有用户
g = Group.objects.get(id=1)
g.user_set.all()
1.3 一对一关系
一对一不是数据库的一个连表操作,而是Django独有的一个连表操作。一对一关系相当于是特殊的一对多关系,只是相当于加了unique=True。
一个人只能有一张身份证,一张身份证对应一个人,是一个典型的一对一关系。
class IdCard(models.Model):
idnum = models.IntegerField()
def __str__(self):
return str(self.idnum)
class Person(models.Model):
idcard = models.OneToOneField(IdCard)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
一对一关系比较简单。两种表互相都有对方。比如:
>>> lisi = Person.objects.get(id=3)
>>> lisi.idcard
<IdCard: 123456>
>>> ids = IdCard.objects.get(id=3)
>>> ids.person
<Person: lisi>
4.F和Q
Q查询——对对象的复杂查询
F查询——专门取对象中某列值的操作
导入Q,F对象 :
from django.db.models import Q,F
F:主要作用
1)和models自身的字段进行对比。比如:
Student.objects.filter(age__gt=F('age2'))
2) 对字段进行数学运算。比如:
Student.objects.filter(age__gt=F('age2') * 2)
Q:
且操作:
默认情况下Django的查询只是且操作如下:
找到用户为zhangsan并且age=18的数据
UserInfo.objects.filter(username='zhangsan',age='18')
或操作:
如果需要执行或操作 ,就需要使用到Q对象了
Q对象可以用 & | ~ (与,或,非)去连接
UserInfo.objects.filter(Q(age__gt=20) & Q(age__lt=50))
UserInfo.objects.filter(Q(age__gt=20) | Q(age__lt=50))
UserInfo.objects.filter(~Q(age__lt=50))
等于: WHERE question LIKE 'Who%' OR question LIKE 'What%'
如果Q和关键字参数一起使用的话,Q必须放在关键字参数前面:
Student.objects.get(Q(age__gt=20) | Q(age__lt=50), name__contains='zhang')
5.models的Manager
django通过models的manager来执行数据库操作。
每个django model至少有一个manager。
可以自定义manager。
自定义manager必须继承自models.Manager
给默认的manager改名:
class Person(models.Model):
...
people = models.Manager()
定制manager
1)增加额外的方法:
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
objects = BookManager()
def __str__(self):
return self.title
2)修改默认manager的查询集
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager, self).get_queryset().filter(author='Roa')
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
3)使用多个manager
class MaleManager(models.Manager):
def get_queryset(self):
return super(MaleManager, self).get_queryset().filter(sex='M')
class FemaleManager(models.Manager):
def get_queryset(self):
return super(FemaleManager, self).get_queryset().filter(sex='F')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=1,
choices=( ('M', 'Male'),
('F', 'Female') )
)
people = models.Manager()
men = MaleManager()
women = FemaleManager()
五 models进阶
1.models基本操作
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
对于ORM框架里:
我们写的类表示数据库的表
如果根据这个类创建的对象是数据库表里的一行数据
那么对象.属性(对象.id 对象.value)就是每一行里的数据
models基本操作
增:
1)创建对象实例,然后调用save方法:
obj = Author(first_name='zhang', last_name='san')
obj.save()
2)使用create方法
Author.objects.create(first_name='li', last_name='si')
3)使用get_or_create方法,可以防止重复
Author.objects.get_or_create(first_name='zhang', last_name='san')
删:
使用Queryset的delete方法:
# 删除指定条件的数据
Author.objects.filter(first_name='zhang').delete()
# 删除所有数据
Author.objects.all().delete()
注意: objects不能直接调用delete方法。
使用模型对象的delete方法:
obj = Author.objects.get(id=5)
obj.delete()
改:
Author.objects.filter(last_name='dfdf').update(last_name='san')
模型没有定义update方法,直接给字段赋值,并调用save,能实现update的功能,比如:
>>> obj = Author.objects.get(id=3)
>>> obj.first_name = 'zhang'
>>> obj.save()
save更新时会更新所有字段。如果只想更新某个字段,减少数据库操作,可以这么做:
obj.first_name = 'li'
obj.save(update_fields=['first_name'])
注意:更新操作不能更新关联表的属性,比如下面的语句是不起作用的。
Author.objects.update(book__title='b')
查:
获取单条数据:Author.objects.get(id=123)
get():返回一个满足条件的对象
如果没有找到符合条件的对象,会引发 模型类.DoesNotExist异常
如果找到多个,会引发 模型类.MultipleObjectsReturned 异常
first():返回查询集中的第一个对象
last():返回查询集中的最后一个对象
count():返回当前查询集中的对象个数
exists():判断查询集中是否有数据,如果有数据返回True没有反之
Author.objects.all() # 获取全部
Author.objects.filter(name='seven') # 获取指定条件的数据
Author.objects.all().values('password') # 获取指定列的值,可以传多个参数!返回包含字典的列表(保存了字段名和对应的值)
Author.objects.all().values_list('password') # 获取指定列的值,可以传多个参数!返回包含元组列表(只保存值)
进阶操作:
# 获取个数
Author.objects.filter(name='seven').count()
#select count(*) from Author where name='seven'
Author.objects.filter(id__gt=1) # 获取id大于1的值
Author.objects.filter(id__gte=1) # 获取id大于或等于1的值
#select * from Author where id>1
Author.objects.filter(id__lt=10) # 获取id小于10的值
Author.objects.filter(id__lte=10) # 获取id小于等于或d10的值
#select * from Author where id<10
Author.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
#select * from Author where id<10 and id>1
Author.objects.filter(id__in=[11, 22, 33]) # 获取id在11、22、33中的数据
#select * from Author where id in (11,22,33)
Author.objects.exclude(id__in=[11, 22, 33]) # not in
#select * from Author where id not in (11,22,33)
Author.objects.filter(name__contains="ven") # contains(和数据中like语法相同)
#select * from Author where name like '%ven%'
#select * from Author where name like '%v\%n%'
Author.objects.filter(name__icontains="ven") # icontains大小写不敏感
Author.objects.filter(name__regex="^ven") # 正则匹配
Author.objects.filter(name__iregex="^ven") # 正则匹配,忽略大小写
Author.objects.filter(id__range=[1, 2]) # 范围bettwen and
# startswith,istartswith, endswith, iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的
Author.objects.filter(name='seven').order_by('id') # asc正序
Author.objects.filter(name='seven').order_by('-id') # desc反序
Author.objects.all()[10:20] #切片,取所有数据的10条到20条,分页的时候用的到,下标从0开始,不能为负数
# 聚合
使用aggregate()函数返回聚合函数的值
Avg:平均值
Count:数量
Max:最大
Min:最小
Sum:求和
from django.db.models import Count, Min, Max, Sum
Author.objects.aggregate(Max('age'))
# 注解
obj = Author.objects.annotate(num_books=Count('book'))
obj[0].num_books
2. 模块关联关系
关系
·分类
·ForeignKey:一对多,将字段定义在多的端中
·ManyToManyField:多对多,将字段定义在两端中
·OneToOneField:一对一,将字段定义在任意一端中
一对多关系,举例说明(一对一, 多对多类似):
一个班级可以有多个学生, 一个学生只能属于一个班级
class Grade(models.Model):
name = models.CharField(max_length=20)
class Student(models.Model):
name = models.CharField(max_length=20)
grade = models.ForeignKey(Grade)
对象的使用:
正向(在Student这边,有grade属性的这一边):
获取学生所在班级(对象): stu.grade
获取学生所在班级的属性: stu.grade.name
反向(在Grade这边):
获取班级的所有学生(获取Manager对象):grade.student_set
获取班级的所有学生(获取QuerySet查询集): grade.student_set.all()
filter(),get()等操作中的使用:
正向(在Student这边,有grade属性的这一边):
Student.objects.filter(属性__name=1)
如:Student.objects.filter(grade__name=1)
反向(在Grade这边):
Grade.objects.filter(类名小写__id=7)
如:Grade.objects.filter(student__id=7)
3. Model连表结构
ORM核心知识回顾:
django根据代码中定义的类来自动生成数据库表。
我们写的类表示数据库的表。
根据这个类创建的对象是数据库表里的一行数据。
对象.id 对象.value 是每一行里的数据
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】
多对多:在某表中创建一行数据时,有一个可以多选的下拉框。
例如:创建用户信息,需要为用户指定多个爱好。
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)
例如:有个身份证表,有个person表。每个人只能有一张身份证,一张身份证也只能对应一个人,这就是一对一关系。
1.1 一对多关系,即外键
为什么要用一对多。先来看一个例子。有一个用户信息表,其中有个用户类型字段,存储用户的用户类型。如下:
class UserInfo(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
user_type = models.CharField(max_length=10)
不使用外键时用户类型存储在每一行数据中。如使用外键则只需要存储关联表的id即可,能够节省大量的存储空间。同时使用外键有利于维持数据完整性和一致性。
当然也有缺点,数据库设计变的更复杂了。每次做DELETE 或者UPDATE都必须考虑外键约束。
刚才的例子使用外键的情况:单独定义一个用户类型表:
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
user_type = models.ForeignKey('UserType')
username = models.CharField(max_length=32)
age = models.IntegerField()
我们约定:
正向操作: ForeignKey在UserInfo表里,如果根据UserInfo去操作就是正向操作。
反向操作: ForeignKey不在UserType里,如果根据UserType去操作就是反向操作。
一对多的关系的增删改查:
正向操作:
增
1)创建对象实例,然后调用save方法:
obj = UserInfo(name='li', age=44, user_type_id=2)
obj.save()
2)使用create方法
UserInfo.objects.create(name='li', age=44, user_type_id=2)
3)使用get_or_create方法,可以防止重复
UserInfo.objects.get_or_create(name='li', age=55, user_type_id=2)
4)使用字典。
dic = {'name':'zhangsan','age':18,'user_type_id':3}
UserInfo.objects.create(**dic)
5)通过对象添加
usertype = UserType.objects.get(id=1)
UserInfo.objects.create(name='li', age=55, user_type=usertype)
删
和普通模式一样删除即可。如:
UserInfo.objects.filter(id=1).delete()
改
和普通模式一样修改即可。如:
UserInfo.objects.filter(id=2).update(user_type_id=4)
查
正向查找所有用户类型为钻石用户的用户,使用双下划线:
users = UserInfo.objects.filter(user_type__caption__contains='钻石')
正向获取关联表中的属性可以直接使用点.语法,比如获取users查询集中第一个用户的caption:
users[0].user_type.caption
反向操作:
增 (一般使用正向增即可)
通过usertype来创建userinfo
1) 通过userinfo_set的create方法
#获取usertype实例
ut = UserType.objects.get(id=2)
#创建userinfo
ut.userinfo_set.create(name='smith',age=33)
删
删除操作可以在定义外键关系的时候,通过on_delete参数来配置删除时做的操作。
on_delete参数主要有以下几个可选值:
models.CASCADE 默认值,表示级联删除,即删除UserType时,相关联的
UserInfo也会被删除。
models.PROTECT 保护模式, 阻止级联删除。
models.SET_NULL 置空模式 设为null,null=True参数必须具备
models.SET_DEFAULT 置默认值 设为默认值,default参数必须具备
models.SET() 删除的时候重新动态指向一个实体访问对应元素 ,可传函数
models.DO_NOTHING 什么也不做。
注意: 修改on_delete参数之后需要重新同步数据库,如果使用
python manage.py shell进行models操作,需要退出shell重新进入。
改
和普通模式一样,不会影响级联表。
查
通过usertype对象来查用户类型为1的用户有哪些
obj=UserType.objects.get(id=1)
obj.userinfo_set.all()
可以通过在定义foreignkey时指定related_name来修改默认的userinfo_set,比如指定related_name为info
user_type = models.ForeignKey('UserType',related_name='info')
指定related_name之后,反向查的时候就变成了:
obj.info.all()
获取用户类型为1且用户名为shuaige的用户
obj.info.filter(username='shuaige')
外键关系中,django自动给usertype加了一个叫做userinfo的属性。使用双下划线,可以通过userinfo提供的信息来查usertype (了解)
user_type_obj = UserType.objects.get(userinfo__username='zs')
1.2 多对多关系
针对多对多关系django会自动创建第三张表。也可以通过through参数指定第三张表。
用户和组是典型的多对多关系:
class Group(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class User(models.Model):
name = models.CharField(max_length=64)
password = models.CharField(max_length=64)
groups = models.ManyToManyField(Group)
def __str__(self):
return self.name
操作:
增:
先分别创建user和group, 再使用add关联
u = User(name='aa', password='123')
u.save()
g = UserGroup(name='g5')
g.save()
通过Manager对象使用add()方法
u.groups.add(g) 或 g.user_set.add(u)
删:
和一对多类似,删除user或group会级联删除user_groups表中的关联数据
改:
和一对多类似,只修改当前表
查:
正向:
查询id=2的用户所在的所有组group
u = User.objects.get(id=2)
u.groups.all()
反向:
查询id=1的组中包含的所有用户
g = Group.objects.get(id=1)
g.user_set.all()
1.3 一对一关系
一对一不是数据库的一个连表操作,而是Django独有的一个连表操作。一对一关系相当于是特殊的一对多关系,只是相当于加了unique=True。
一个人只能有一张身份证,一张身份证对应一个人,是一个典型的一对一关系。
class IdCard(models.Model):
idnum = models.IntegerField()
def __str__(self):
return str(self.idnum)
class Person(models.Model):
idcard = models.OneToOneField(IdCard)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
一对一关系比较简单。两种表互相都有对方。比如:
>>> lisi = Person.objects.get(id=3)
>>> lisi.idcard
<IdCard: 123456>
>>> ids = IdCard.objects.get(id=3)
>>> ids.person
<Person: lisi>
4.F和Q
Q查询——对对象的复杂查询
F查询——专门取对象中某列值的操作
导入Q,F对象 :
from django.db.models import Q,F
F:主要作用
1)和models自身的字段进行对比。比如:
Student.objects.filter(age__gt=F('age2'))
2) 对字段进行数学运算。比如:
Student.objects.filter(age__gt=F('age2') * 2)
Q:
且操作:
默认情况下Django的查询只是且操作如下:
找到用户为zhangsan并且age=18的数据
UserInfo.objects.filter(username='zhangsan',age='18')
或操作:
如果需要执行或操作 ,就需要使用到Q对象了
Q对象可以用 & | ~ (与,或,非)去连接
UserInfo.objects.filter(Q(age__gt=20) & Q(age__lt=50))
UserInfo.objects.filter(Q(age__gt=20) | Q(age__lt=50))
UserInfo.objects.filter(~Q(age__lt=50))
等于: WHERE question LIKE 'Who%' OR question LIKE 'What%'
如果Q和关键字参数一起使用的话,Q必须放在关键字参数前面:
Student.objects.get(Q(age__gt=20) | Q(age__lt=50), name__contains='zhang')
5.models的Manager
django通过models的manager来执行数据库操作。
每个django model至少有一个manager。
可以自定义manager。
自定义manager必须继承自models.Manager
给默认的manager改名:
class Person(models.Model):
...
people = models.Manager()
定制manager
1)增加额外的方法:
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
objects = BookManager()
def __str__(self):
return self.title
2)修改默认manager的查询集
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager, self).get_queryset().filter(author='Roa')
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
dahl_objects = DahlBookManager() # The Dahl-specific manager.
3)使用多个manager
class MaleManager(models.Manager):
def get_queryset(self):
return super(MaleManager, self).get_queryset().filter(sex='M')
class FemaleManager(models.Manager):
def get_queryset(self):
return super(FemaleManager, self).get_queryset().filter(sex='F')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=1,
choices=( ('M', 'Male'),
('F', 'Female') )
)
people = models.Manager()
men = MaleManager()
women = FemaleManager()
#六 视图以及返回
1. 视图及HttpRequest 和HttpResponse
Django中的视图主要用来接受Web请求,并做出响应。
视图的本质就是一个Python中的函数
视图的响应分为两大类
1)以Json数据形式返回 (JsonResponse)
2)以网页的形式返回
2.1)重定向到另一个网页 (HttpResponseRedirect)
2.2)错误视图(40X,50X) ( HttpResponseNotFound,HttpResponseForbidden,HttpResponseNotAllowed等)
视图响应过程: 浏览器输入 -> django获取信息并去掉ip:端口,剩下路径 -> urls 路由匹配 - > 视图响应 -> 回馈到浏览器
视图参数:
1) 一个HttpRequest的实例,一般命名为request
2) 通过url正则表达式传递过来的参数
位置:通常在应用下的views.py中定义
错误视图:
1) 404视图 (页面没找到)
2) 400视图 (客户操作错误)
3) 500视图(服务器内部错误)
自定义错误视图
在工程的templates文件夹下创建对应的错误文件
在文件中定义自己的错误样式
注意需要在关闭Debug的情况下才可以
没有关闭Debug的情况下会在界面中直接显示log
1.1 HttpRequest
服务器在接收到Http请求后,会根据报文创建HttpRequest对象
视图中的第一个参数就是HttpRequest对象
Django框架接收到http请求之后会将http请求包装为HttpRequest对象,之后传递给视图。
HttpRequest和HttpResponse属性和方法的详细说明
常用属性和方法:
属性: path 请求的完整路径
method 请求的方法,常用GET,POST
encoding 编码方式,常用utf-8
GET 类似字典的参数,包含了get的所有参数
POST 类似字典的参数,包含了post所有参数
FILES 类似字典的参数,包含了上传的文件
COOKIES 字典,包含了所有COOKIE
session 类似字典,表示会话
方法: is_ajax() 判断是否是ajax(),通常用在移动端和JS中
get_full_path() 返回包含参数字符串的请求路径.
QueryDict
类似字典的数据结构。与字典的区别,可以存在相同的键。
QueryDict中数据获取方式
dict['uname'] 或 dict.get('uname')
获取指定key对应的所有值
dict.getlist('uname')
1.2 HttpResponse
服务器返回给客户端的数据
HttpResponse由程序猿自己创建:
1)不使用模板,直接调用HttpResponse(),返回HttpResponse对象。
2)调用模板,进行渲染。
2.1) 先load模板,再渲染
2.2) 直接使用render一步到位
render(request,template_name[,context])
request 请求体对象
template_name 模板路径
context 字典参数,用来填坑
属性: content 返回的内容
charset 编码格式
status_code 响应状态码(200,3xx,404,5xx)
方法
init 初始化内容
write(xxx) 直接写出文本
flush() 冲刷缓冲区
set_cookie(key,value='xxx',max_age=None,expries=None)
delete_cookie(key) 删除cookie,上面那个是设置
HttpResponse子类
HttpResponseRedirect
响应重定向:可以实现服务器内部跳转
return HttpResponseRedict('/grade/2017')
使用的时候推荐使用反向解析
JsonResponse
返回Json数据的请求,通常用在异步请求上
JsonResponse(dict)
也可以使用__init__(self,data)设置数据
Content-type是application/json
2. Cookies 和Session
2.1 Cookies
理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆. 而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容
cookie本身由服务器生成,通过Response将cookie写到浏览器上,下一次访问,浏览器会根据不同的规则携带cookie过来。
注意:cookie不能跨浏览器
设置cookie(使用response设置):
response.set_cookie(key,value[,max_age=None,expries=None)]
max_age: 整数 单位为秒,指定cookie过期时间
expries : 整数,指定过期时间,还支持datetime或timedelta,可以指定一个具体日期时间
max_age和expries两个选一个指定
过期时间的几个关键时间
max_age 设置为 0 浏览器关闭失效
设置为None永不过期
expires=timedelta(days=10) 10天后过期
# response.set_cookie('username', username, max_age=10)
获取cookie(使用request获取):
request.COOKIES.get('username')
删除cookie(使用response删除):
response.delete_cookie('username')
cookie存储到客户端
优点:
数据存在在客户端,减轻服务器端的压力,提高网站的性能。
缺点:
安全性不高:在客户端机很容易被查看或破解用户会话信息
2.2 Session
服务器端会话技术,依赖于cookie.
django中启用SESSION
settings中
INSTALLED_APPS:
'django.contrib.sessions'
MIDDLEWARE:
'django.contrib.sessions.middleware.SessionMiddleware'
基本操作
设置Sessions值(使用request设置)
request.session['username'] = username
获取Sessions值
get(key,default=None) 根据键获取会话的值
username = request.session.get("username")
# 或 session_name = request.session["session_name"]
删除Sessions值
del request.session["session_name"]
clear() 清楚所有会话
flush() 删除当前的会话数据并删除会话的cookie
session.session_key获取session的key
数据存储到数据库中会进行编码,使用的是Base64
每个HttpRequest对象都有一个session属性,也是一个类字典对象.
七 token&静态文件&媒体文件
1. token
1. 会话技术
2. 服务端会话技术
3. 它实际上就是手动实现的session
4. 实现token
4.1 在models.py中User类中添加token字段
class User(models.Model):
name = models.CharField(max_length=30, unique=True)
password = models.CharField(max_length=32)
age = models.IntegerField(default=1)
token = models.CharField(max_length=32, null=True, blank=True, default='')
4.2 md5加密
# md5加密
def my_md5(password):
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
return md5.hexdigest()
4.3 注册用户时,随机生成唯一的token
token/usertoken, 用户唯一标识
可以使用 时间+随机数+公司域名+ip信息 或 时间+随机数等方式生成token
# 生成加密的token
def generate_token():
token = str(time.time()) + str(random.random())
return my_md5(token)
4.4 登录时使用cookie存储token
# token
d = datetime.datetime.now() + datetime.timedelta(days=7) # 保存7天
response.set_cookie('token', res.first().token, expires=d)
4.5 根据token获取用户信息
token = request.COOKIES.get('token', '')
users = User.objects.filter(token=token)
4.6 退出登录
response = HttpResponseRedirect(reverse('app:index'))
# 删除cookie: token
response.delete_cookie('token')
return response
2. 用户登录注册
1. 用户注册
将用户名,用户密码,用户信息,存储到数据库中
2. 用户登陆
使用用户名,用户密码进行数据库校验
3. 用户信息
根据用户的唯一标识,去获取用户
4. 数据安全
服务器的数据对任何人来说都应该是不可见的(不透明)
可以使用常见的摘要算法对数据进行摘要(md5,sha1)
如果使用了数据安全,那么就需要在所有数据验证的地方都加上 数据安全
3. 静态文件和媒体文件
媒体文件:用户上传的文件,叫做media
静态文件:存放在服务器的css,js,image等 叫做static
3.1 在django中使用静态文件
1)首先确保django.contrib.staticfiles在 INSTALLED_APPS中
2)在settings中定义 STATIC_URL
STATIC_URL = '/static/'
3)在你app的static目录中存放静态文件,比如:
my_app/static/my_app/example.jpg.
4)如果有别的静态资源文件,不在app下的static目录下,可以通过
STATICFILES_DIRS来指定额外的静态文件搜索目录。
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
...
]
5)在模板中使用load标签去加载静态文件
{% load static %}
<img src="{% static "my_app/example.jpg" %}" alt="My image"/>
3.2 在django中使用媒体文件
1)在settings中配置 MEDIA_ROOT
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
4. 文件上传
文件上传要求form表单存在enctype="multipart/form-data"属性,并且提交方法是post。
<form enctype="multipart/form-data" action="/uploadFile/" method="post">
<input type="file" name="myfile" />
<br/>
<input type="submit" value="upload"/>
</form>
最简单的文件上传:
def file_upload(request):
if request.method == 'POST':
# 获取上传的文件,如果没有文件,则默认为None
myFile = request.FILES.get('myfile', None)
if not myFile:
return HttpResponse("no files for upload")
file_path = os.path.join(settings.MEDIA_ROOT, '1.jpg')
with open(file_path, 'ab') as fp:
for part in myFile.chunks():
fp.write(part)
return HttpResponse("上传成功!")
else:
return render(request, 'index.html')
5. 多文件上传
多文件上传和单文件上传类似
1.需要在模板文件的form表单input中添加multiple
2.后台获取时使用request.FILES.getlist('myfile', None)
def file_upload2(request):
if request.method == 'POST':
# 获取上传的文件,如果没有文件,则默认为None
myFiles = request.FILES.getlist('myfile', None)
for myFile in myFiles:
if not myFile:
return HttpResponse("no files for upload")
file_path = os.path.join(settings.MEDIA_ROOT, myFile.name)
with open(file_path, 'ab') as fp:
for part in myFile.chunks():
fp.write(part)
return HttpResponse("上传成功!")
else:
return render(request, 'index.html')
6.分页
6.1 分页工具
django提供了分页的工具,存在于django.core中
Paginator : 数据分页工具
Page : 具体的某一页面
导入Paginator:
from django.core.paginator import Paginator
Paginator:
对象创建:
Paginator(数据集,每一页数据数)
属性:
count:对象总数
num_pages:页面总数
page_range: 页码列表,从1开始
方法:
page(整数): 获得一个page对象
常见错误:
InvalidPage:page()传递无效页码
PageNotAnInteger:page()传递的不是整数
Empty:page()传递的值有效,但是没有数据
Page:
对象获得,通过Paginator的page()方法获得
属性:
object_list: 当前页面上所有的数据对象
number: 当前页的页码值
paginator: 当前page关联的Paginator对象
方法:
has_next() :判断是否有下一页
has_previous():判断是否有上一页
has_other_pages():判断是否有上一页或下一页
next_page_number():返回下一页的页码
previous_page_number():返回上一页的页码
len():返回当前页的数据的个数
八 中间件&缓存
1. 中间件&AOP
中间件:是一个轻量级的,底层的插件,可以介入Django的请求和相应过程(面向切面编程)
中间件的本质就是一个python类
面向切面编程(Aspect Oriented Programming)简称AOP。AOP的主要实现目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合的隔离效果。
中间件可实现功能
- 统计
- 黑名单
- 白名单
- 反爬
- 界面友好化(捕获异常)
1.1 中间件的可切入点
[外链图片转存失败(img-4l5iMiIL-1568786244369)(G:/web%E6%A1%86%E6%9E%B6/Django/day08/doc/1525190616689.png)]
1.2 切入函数
__init__:
没有参数,服务器响应第一个请求的时候自动调用,用户确定是否启用该中间件
process_request(self,request):
在执行视图前被调用,每个请求上都会调用,不主动进行返回或返回HttpResponse对象
process_view(self,request,view_func,view_args,view_kwargs):
调用视图之前执行,每个请求都会调用,不主动进行返回或返回HttpResponse对象
process_template_response(self,request,response):
在视图刚好执行完后进行调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象
process_response(self,request,response):
所有响应返回浏览器之前调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象
process_exception(self,request,exception):
当视图抛出异常时调用,不主动进行返回或返回HttpResponse对象
1.3 自定义中间件
自定义中间件流程
1.在工程目录下创建middleware目录
2.目录中创建一个python文件
3.在python文件中导入中间件的基类
from django.utils.deprecation import MiddlewareMixin
4.在类中根据功能需求,创建切入需求类,重写切入点方法
class LearnAOP(MiddlewareMixin):
def process_request(self,request):
print('request的路径',request.GET.path)
5.启用中间件,在settings中进行配置,MIDDLEWARE中添加middleware.文件名.类名
2. Cache
https://docs.djangoproject.com/zh-hans/2.0/topics/cache/
缓存框架的核心目标
- 较少的代码
- 缓存应该尽可能快
- 因此围绕缓存后端的所有框架代码应该保持在绝对最小值,特别是对于获取操作
- 一致性
- 缓存API应该是提供跨越不同缓存后端的一致接口
- 可扩展性
- 基于开发人员的需求,缓存API应该可以在应用程序级别扩展
缓存
- django内置了缓存框架,并提供了几种常用的缓存
- 基于Memcached缓存
- 使用数据库进行缓存
- 使用文件系统进行缓存
- 使用本地内存进行缓存
- 提供缓存扩展接口
缓存配置
-
创建缓存表
python manage.py createcachetable [table_name]
-
缓存配置
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', 'TIMEOUT': '60', 'OPTIONS': { 'MAX_ENTRIES': '300', }, 'KEY_PREFIX': 'jack', 'VERSION': '1', } }
缓存使用
- 在视图中使用(使用最多的场景)
- @cache_page()
- time 秒 60*5 缓存五分钟
- cache 缓存配置, 默认default,
- key_prefix 前置字符串
缓存底层
获取cache
from django.core.cache import cache
cache = cache['cache_name'] 或 cache = cache.get('cache_name')
设置cache
from django.core.cache import cache
cache.set(key, value, timeout)
使用原生缓存来实现
def get_user_list(request):
# 每次从缓存中获取
user_cache = cache.get('user_cache')
# 如果有缓存,则从缓存中直接取
if user_cache:
result = user_cache
# 如果没有缓存,则从数据库中获取
else:
# 模拟长时间的数据操作
user_list = User.objects.all()
time.sleep(5)
data = {
'users': user_list,
}
# 使用模板渲染,得到result文本
template = loader.get_template('App/stu_list.html')
result = template.render(data)
# 设置缓存
cache.set('user_cache', result, 10)
return HttpResponse(result)
##九 项目开发流程&项目架构
1. 软件开发的一般流程
[外链图片转存失败(img-1nM0TBoP-1568786244370)(G:/web%E6%A1%86%E6%9E%B6/Django/day09/doc/%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E7%9A%84%E4%B8%80%E8%88%AC%E6%B5%81%E7%A8%8B.png)]
1. 需求分析及确认:
由需求分析工程师与客户确认甚至挖掘需求。输出需求说明文档。
2. 概要设计及详细设计:
开发对需求进行概要设计,包括系统的基本处理流程,组织结构、模块划分、接口设计、数据库结构设计等。然后在概要设计的基础上进行详细设计。详细设计中描述实现具体模块所涉及到的主要算法、数据结构、类的层次结构及调用关系,需要说明软件系统各个层次中的每一个程序(每个模块或子程序)的设计考虑,以便进行编码和测试。基本达到伪代码的层面。
3. 编码:
根据详细设计文档进行编码。在实际的项目开发中,编码是占时间最少的。
4. 测试:
一般有专业测试团队进行测试。
5. 发布或上线:
提供各种文档,比如杀毒软件扫描文档,安装手册,操作指南等一系列文档资料打包与程序一起发布。当然后续还会有验收和维护等操作。
2. 企业常见开发模式
1.瀑布模型式:
瀑布模型式是最典型的预见性的方法,严格遵循预先计划的需求分析、设计、编码、集成、测试、维护的步骤顺序进行。瀑布式的主要的问题是它的严格分级导致的自由度降低,项目早期即作出承诺导致对后期需求的变化难以调整,代价高昂。瀑布式方法在需求不明并且在项目进行过程中可能变化的情况下基本是不可行的。
2.迭代式开发 (目前公司用的较多的开发模式)
每次只设计和实现这个产品的一部分;
逐步逐步完成的方法叫迭代开发;
每次设计和实现一个阶段叫做一个迭代.
在迭代式开发方法中,整个开发工作被组织为一系列的短小的、
固定长度(如3周)的小项目,被称为一系列的迭代。
每一次迭代都包括了需求分析、设计、实现与测试。
3.敏捷开发 (比较热门的开发模式)
和迭代式开发类似,敏捷开发的周期可能更短,并且更加强调队伍中的高度协作。一个小功能叫做一个story。开发人员要完成stroy文档的编写。
3, 项目架构搭建
3.1 项目目录结构
[外链图片转存失败(img-MZ49Hkow-1568786244370)(G:/web%E6%A1%86%E6%9E%B6/Django/day09/doc/%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84.bmp)]
3.2 创建项目
django-admin startproject blog
3.3 创建App
单独打开blog项目, 选择运行环境, 并创建App
python manage.py startapp App
3.4 项目配置
打开settings.py进行如下配置
1,设置允许主机为所有, ALLOWED_HOSTS = ["*"]
2,在INSTALLED_APPS中注册App
3, 在项目根目录下创建templates目录,并在settings.py中TEMPLATES给DIRS添加路径
4, 在mysql中创建新数据库blog, 并配置数据库为mysql,
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'axf',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': 'root',
}
}
5, 设置语言为中文:
LANGUAGE_CODE = 'zh-hans'
6, 设置时区:
TIME_ZONE = 'Asia/Shanghai'
7, 配置静态文件和媒体文件目录
7.1 在根目录下创建static目录, 并在static目录中创建uploads目录
7.2 在setting.py中配置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/uploads')
3.5 目录结构
static目录
根据项目需求在static目录中创建以下目录:
应用目录app
样式目录css
字体目录fonts
图片目录img
脚本文件目录js
媒体文件目录uploads
且在app目录下针对每个功能模块分别创建以下目录,分别存放每个功能模块的静态文件
首页home
购物车cart
我的mine
templates目录
根据项目需求在templates中创建以下目录和文件, 分别存放每个功能模块的模板
首页home
闪购market
购物车cart
我的mine
基础模板: base.html
主体模板: base_main.html
3.6 App配置
在App中创建并配置urls.py文件,并配置好工程
urls.py的路由规则
3.7 编写代码
此处省略一万行代码...
- 创建一个django
django-admin startproject 名字 (在cmd)
在linux里要加.py
-
在django创建一个包
python manage.py startapp 名字 (在terminal)
-
文件夹指定成存入html文件
os.path.join(BASE_DIR,(文件名))