Python下有许多款不一样的 Web 框架。Django是重量级选手中最有表明性的一位。许多成功的网站和APP都基于Django。html
Django是一个开放源代码的Web应用框架,由Python写成。前端
Django遵照BSD版权,初次发布于2005年7月, 并于2008年9月发布了第一个正式版本1.0 。python
Django采用了MVC的软件设计模式,即模型M,视图V和控制器C。mysql
因此Django的设计目标就是一款大而全,便于企业开发项目的框架,所以企业应用较为普遍 react
1 可以快速开发,如Auth,Cache模板
2 MVC设计模式
3 实用的管理后台
4 自带ORM,Template,Form,Auth核心
5 组件
6 简洁的URL设计
7 周边插件丰富 git
重量级,由于东西大而全
同步阻塞web
Django version | python version |
---|---|
1.8 | 2.7 3.2 3.3 3.4 3.5 |
1.9 1.10 | 2.7 3.4 3.5 |
1.11 | 2.7 3.4 3.5 3.6 |
2.0 | 3.4 3.5 3.6 |
2.1 | 3.5 3.6 3.7 |
建议不要随便尝试新版本,由于其可能会有问题sql
python3.5.4 Django 版本2.0 数据库
mkdir test // 建立test目录 pyenv virtualenv 3.5.4 test //建立test虚拟帐号 cd test/ pyenv local test //设置虚拟环境
结果以下 django
pip install django==2.0
建立名称为test.dj的项目
django-admin startproject testdj .
项目结构以下
上述命令就在当前目录中建立了Django项目的初始化文件,点表示项目的根目录
重要文件说明
manage.py:本项目管理的命令行工具,应用建立,数据库迁移,等都须要其完成, testdj/settings.py: 本项目配置文件,数据库参数等 testdj/urls.py:URL路径映射配置,默认状况下,只配置了/admin的路由 testdj/wsgi:定义WSGI接口信息,通常无需改动
设置本地项目路径
链接远端项目
链接远端
远端地址
SSH链接
若端口不一样可修改端口
配置密码
配置项目映射和相关项目环境
结果以下
数据拉取
数据库必须启动,其用户名密码必须存在
建立test库
Django链接配置
相关参数详解
'ENGINE' : 链接引擎
'NAME':链接数据库用户名
'PASSWORD':链接数据库密码
'HOST':数据库主机IP地址,缺省字符串,表明localhost,若是是'/'开头表示Unix socket 链接
'POST':端口
数据库引擎ENGINE
内建的引擎有
django.db.backends.postgresql django.db.backends.mysql django.db.backends.sqlite3 django.db.backends.oracle
django 在配置时须要加载mysql的配置,所以其是全局配置,链接数据库的配置,在启动时必须被加载,其中settings.py是最先被加载的
数据库驱动配置
驱动地址
https://docs.djangoproject.com/en/2.2/ref/databases/#mysql-notes
Django支持MySQL 5.5+
Django的官方推荐版本是mysql 1.3.7 +
安装驱动
pip install mysqlclient
结果以下
执行迁移文件,其自己的数据库配置
python manage.py migrate
结果以下
python manage.py startapp testapp
admin.py 管理站点模型的声明文件
models.py 模型层Model类定义
views.py 定义URL 响应函数
migrations包。数据库迁移文件生成目录
apps.py 应用的信息定义文件
在 settings.py中,增长testapp应用,目的是为了后台管理admin使用。或者迁移 migrate 使用
1 建立管理员
设置用户名为admin,密码为admin123
./manage.py createsuperuser
结果以下
修改配置文件容许全部主机访问
启动
python manage.py runserver 0.0.0.0:8000
默认启动为8000端口
以下
若是使用react实现前端的页面功能,其实Django就不必使用模板,它其实就是一个后台服务器程序,接受请求,响应数据,接口设计就能够是一个纯粹的Reasrful 风格
模板的目的就是为了可视化,将数据按照必定的布局格式输出,而不是为了数据处理,因此通常不会有复杂的逻辑,模板的引入实现了业务逻辑和显示格式的分离,这样,在开发中,就能够分工工做,页面开发完成的页面布局设计,后台开发完成数据处理逻辑的实现
python的模板引擎默认使用Django template language (DTL)构建
在settins.py中,设置模板项目的路径
名词解释
DIRS 列表,定义模板文件的搜索路径顺序
BACKEND 指定项目默认引擎
APP_DIRS 是否运行在每一个已安装的应用中查找模板
BASE_DIR 是项目的根目录,os.path.join(BASE_DIR,'templates')就是在manage.py这层创建一个目录templates,这路径是后面找模板的地方。
项目目录中添加相关文件夹并在其中建立index.html文件
模板处理2个步骤
1 加载模板
模板是一个文件,须要从磁盘中读取并加载,要将模板放置在上述指定的目录中2 渲染
模板须要使用内容数据来渲染,生成对应的HTML文件内容
在testdj/urls.py中配置以下
相关代码
from django.contrib import admin from django.urls import path from django.conf.urls import url # 导入url用于匹配多个后缀服务 from django.shortcuts import render # 导入渲染模板 def index(request): print (request) print (type(request)) return render(request,'index.html',{'user':'hello world'}) urlpatterns = [ url(r'^admin/', admin.site.urls), # 正则匹配,以admin 开头的调度到admin.site.urls中 url(r'^index/',index), #同上 url(r'^$',index), ]
render 源码以下
def render(request, template_name, context=None, content_type=None, status=None, using=None): """ Return a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments. """ content = loader.render_to_string(template_name, context, request, using=using) return HttpResponse(content, content_type, status)
上述中还能够传递状态码等参数,但第一个必须是request,第二个必须是模板名称,
处理模块填充相关问题
def render_to_string(template_name, context=None, request=None, using=None): """ Load a template and render it with a context. Return a string. template_name may be a string or a list of strings. """ if isinstance(template_name, (list, tuple)): template = select_template(template_name, using=using) # 解决模板找到模板名称的问题,在配置文件中寻找 else: template = get_template(template_name, using=using) return template.render(context, request) # 此处是使用模板来填充数据,并将其输出出来,其中包含请求和响应内容
搜索模板相关代码
def get_template(template_name, using=None): """ Load and return a template for the given name. Raise TemplateDoesNotExist if no such template exists. """ chain = [] engines = _engine_list(using) for engine in engines: try: return engine.get_template(template_name) except TemplateDoesNotExist as e: chain.append(e) raise TemplateDoesNotExist(template_name, chain=chain)
index 代码以下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> test <h1>{{ user }}</h1> <!--此处必须和前面的最后一列中的名称相对应,不然将不能被识别到--> </body> </html>
加载方法至关于使用open将文件打开,渲染方法将其中的{{}}中的内容进行填充,填充好后交给httpresponse 的body,进行传递头部,约定编码,相关压缩状况,当正文来了后先看编码格式,后看title,最后加载body的渲染内容
下载是不渲染的,发起HTTP请求,服务器将文件打开,文件流传输,其类型是普通文件,其不会渲染成dom树,其不会作相关的操做,下载不须要dom,只有转换成DOM才能渲染,
from django.contrib import admin from django.urls import path from django.http import HttpResponse,JsonResponse from django.conf.urls import url # 导入url用于匹配多个后缀服务 from django.shortcuts import render # 导入渲染模板 def index(request): print (request) print (type(request)) return JsonResponse({'user':'hello world'}) # 此处返回结果为一个json格式的数据 urlpatterns = [ url(r'^admin/', admin.site.urls), # 正则匹配,以admin 开头的调度到admin.site.urls中 url(r'^index/',index), #同上 url(r'^$',index), ]
构建结果以下
https://docs.djangoproject.com/en/2.2/ref/templates/builtins/
语法 {{variable}}
变量名由字母,数字,下划线,点号组成
点号使用时,须要遵循的顺序:
1 字典查找,如foo['bar'],把foo当作字典,bar当作key
2 属性或方法的查找,如foo.bar 是把foo当作对象,bar当作属性或者方法
3 数字索引查找,如foo[bar],把foo当作列表同样,将使用索引访问
若是变量未能找到,则缺省插入空字符串
在模板中调用方法,不能加小括号,天然也不能传递参数
{{ my_dict.keys }} 这样是对的,不能写成 {{ my_dict.keys() }}
基本语法以下
{% if condition %}
... display
{%end%}或者
{% if condition1 %}
..display 1
{% elif condition2 %}
...display 2
{% else %}
...display 3
{% endif %}条件也支持and,or,not
注意:由于这些标签是断开的,因此不能像python同样使用锁紧就能够表示出来,必须有一个结束表亲,如 endif endfor
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <ul> {% for x in name %} <li> {{ x }} </li> {% endfor %} </ul> </body> </html>
下面是便利字典的值
return render(request,'index.html',{'name':dict(zip('abcd',range(4)))})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <ul> {% for x in name.values %} <li> {{ x }} </li> {% endfor %} </ul> </body> </html>
结果以下
变量 | 说明 |
---|---|
forloop.counter | 当前循环从1开始计数 |
forloop.counter 0 | 当前循环从0开始计数 |
forloop.revcounter | 从循环的末尾开始倒计数到1 |
forloop.revcounter0 | 从循环的末尾开始倒计数到0 |
forloop.first | 第一次进入循环 |
forloop.last | 最后一次进入循环 |
forloop.parentloop | 循环嵌套时,内存当前玄幻的外层循环 |
return render(request,'index.html',{'name': [1,2,3,4,5,6]})
翻转,此处仅限于列表
<ul> {% for x in name reversed %} <li> {{ x }} </li> {% empty %} <li> default </li> {%endfor%} </ul>
empty ,为空或者不存在时执行此命令
以下
<ul> {% for x in mysql reversed %} <li> {{ x }} </li> {% empty %} <li> default </li> {%endfor%} </ul>
此处的mysql是不存在的,所以下面的结果是
后端代码以下
return render(request,'index.html',{'name': dict(zip('abcd',range(4)))})
<ul> {% for k,v in name.items %} <li> {{ forloop.first }} </li> <li> {{ forloop.last }} </li> {%endfor%} </ul> <h1> 分割线 </h1> <ul> {% for k,v in name.items %} <li> {{ forloop.counter}} {{ k }} {{ v }} </li> {%endfor%} </ul> <h1> 分界线 </h1> <ul> {% for k,v in name.items %} <li> {{ forloop.counter0 }} {{ k }} {{ v }} </li> {%endfor%} </ul>
结果以下
{% ifequal %} 标签比较两个值,当其相等时,显示在其标签之间的全部值,
{%ifequal user currentuser %}
<h1> welcome! </h1>
{% endifequal %}和{% if %}相似,{% ifequal %} 支持可选的 {% else %}标签。
后端代码以下
return render(request,'index.html',{'name': 'mysql'})
显示层代码以下
{% ifequal name 'mysql' %} <h1> Site </h1> {%else%} <h1>Not Site </h1> {%endifequal%} </body> </html>
csrf_token 用于跨站请求伪造保护,防止跨站***的
{% csrf_token%}
单行注释
{#这是一个注释#}
多行注释
{% comment %}
这是多行注释
{%endcomment%}
模板过滤器能够在变量被显示以前修改它
语法 {{ 变量 | 过滤器 }}
过滤器使用管道符 | , 例如 {{name| lower}} , {{name}} 变量被过滤器 lower 处理后,文档大写转换文本为小写。
过滤管道能够被套接,一个过滤器管道的输出又能够做为下一个管道的输入,例如{{my_list | first | upper }},将列表第一个元素并将其转换为大写。
过滤器传递参数
有些过滤器能够被传递参数,过滤器的参数跟随冒号以后而且老是以双引号包含如 {{bio| trunactewords:"30"}},截取显示变量的bio的前30个词。
{{my_list | join:"."}}将my_list的全部元素使用逗号链接起来
过滤器 | 说明 | 举例 | ||
---|---|---|---|---|
first | 取列表第一个元素 | |||
last | 去列表最后一个元素 | |||
yesno | 变量能够是 True,False,None,yesno的参数给定的逗号分隔的三个值,返回3个值中的一个。True对应飞一个,False对应第二个,None对应第三个,若是参数只有2个,则None等效于False处理 | {{value | yesno:"yeah,no,maybe"}} | |
add | 加法,参数是负数就是减法 | 数字加{{value | add:"100"}} 列表合并{{mylist | add:newlist}} |
divisibleby | 可否被整除 | {{vaule | divisibleby:"3"}}可以被3整除返回True | |
addslashes | 在反斜杠,单引号或者双引号前面加上反斜杠 | {{value | addslashes}} | |
length | 返回变量的长度 | {% if my_list | length >1 %} | |
default | 变量等价False则使用缺省值 | {{value | default:"nothing"}} | |
default_if_none | 变量为None使用缺省值 | {{value | default_if_none:"noting"}} |
练习
计数返回一种类型的值,偶数返回一种类型的颜色
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <u1> {% for v in name.values %} {% if forloop.counter0|divisibleby:"2" %} <li style="color:red"> {{ v }} </li> {% else %} <li style="color:seagreen"> {{ v }} </li> {% endif %} {% endfor %} </u1> </body> </html>
第二种
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页</title> </head> <body> <u1> {% for v in name.values %} <li style='color: {{ forloop.counter0 | divisibleby:"2"| yesno:"red,blue"}}'>{{v}}</li> {% endfor %} </u1> </body> </html>
结果以下
Django 会为模型提供一个object对象,其是Django.db.models.manager.Manager类型,用于与数据库交互,当定义模型类的时候没有指定管理器,则Django会为模型类提供一个object管理器。
若是在模型中手动指定管理器后,Django不在提供默认的object管理器了
管理器是Django的模型进行数据库查询操做的接口,Django应用的每个模型都至少拥有一个管理器。
查询会返回结果的集,是Django.db.models.query.QuerySet类型
其是惰性求值,和sqlalchemy同样,结果就是查询的集。
其是可迭代对象。
1 惰性求值:
建立查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库,在迭代,序列化,if语句中都会当即求值。2 缓存
每个查询都包含一个缓存,来最小化对数据库的访问
新建查询集,缓存为空,首次对查询集请求值时,会发生数据查库查询,Django会把查询的结果缓存在这个缓存中,并返回请求的结果,接下来对查询集的求值将使用缓存的结果。
观察下面2个例子是要看真正生成的语句了
1 没有使用缓存,每次都要查询数据库,查询了两次
[user.name for user in User.objects.all()]
[user.name for user in User.objects.all()]2 下面的语句使用缓存,由于其使用同一个结果集
qs = User.objects.all()[user.name for user in qs ]
[user.name for user in qs ]
查询集对象能够直接使用索引下表的方式(不支持负向索引),至关于SQL语句中的limit 和 offset 字句,注意使用索引返回的新结果集,依然是惰性求值,不会当即查询。
qs = User.objects.all()[20:40]
SQL 等价:Limit 20 offset 20
qs = User.obeject.all()[20:30]
SQL 等价:Limit 10 offset 20
column | column |
---|---|
all() | Text |
filter() | 过滤,返回知足条件查询的数据 |
exclude() | 排除,排除知足条件的数据 |
order_by() | |
values() | 返回一个对象的字典的列表,像JSON |
下属等价
filter(k1=v1).filter(k2=v2)等价于 filter(k1=v1,k2=v2)
filter(pk=10)这里pk指的是主键,不用关心主键的名字字段,固然也可使用主键来进行相关的过滤操做
返回单值的状况
column | column |
---|---|
get() | 仅返回单个知足条件的对象,若是未能返回对象则排除DoesNotExists异常,若是能返回多条,抛出MultipleObjectReturned 异常 |
count() | 返回当前查询的总条数 |
first() | 返回第一个对象 |
last() | 返回最后一个对象 |
exist() | 判断查询集中是否有数据,若是有则返回True |
字段查询(field Lookup) 表达式
字段查询表达式能够做为filter(),exclude(),get() 的参数,实现的是where字句的功能语法: 属性(字段) 名称_比较运算符=值
注意: 属性名和运算符之间使用双下划线
column | column | |
---|---|---|
exact | filter(isdeleted=False) filter(isdeleted__exact=False) | 严格等于,能够省略不写 |
contains | exclude(title__contains='天') | 是否包含,大小写敏感,等价于 like '%天%' |
startswith endswith | filter(title__startswith='天') | 以什么开头,以什么结尾,大小写敏感 |
isnull isnotull | filter(title__isnull=False) | 是否为null |
iexact,iconains,istartswitch,iendswith | i 的意思是忽略大小写 | |
in | filter(pk__in=[1,2,3,4]) | 是否在指定返回的数据中 |
gt,gte,lt,lte | filter(id__gt=3) filter(pk__ltd=3),filter(pub_date__gt=date(2000,1,1)) | 大于,小于等 |
year,month,day,week_day,hour,minute,second | filter(pub_date__year=2000) 对日期类型属性处理 |
虽然Django 提供传入条件的方式,可是不方便,它还提供了Q对象来解决。
Q对象是Django.db.modules.Q,可使用 &(and) , |(or)操做符来组成逻辑表达式,~ 表示not
from django.db.models import Q User.objects.filter(Q(pk__lt=6)) # 不如直接写 User.objects.filter(pk<6) User.objects.filter(pk__gt=6).filter(pk_lt=10) #与 User.objects.filter(Q(pk__gt=6) & (pk__lt=10)) # 与 User.objects.filter(Q(pk=6) | Q(pk=10)) # 或 User.objects.filter(~Q(pk__lt<6)) # 非
可以使用&| 和Q对象来构造复杂的逻辑表达式
过滤器函数可使用一个或多个Q对象
若是混用关键字参数和Q对象,那么Q对象必须位于关键字参数的前面,全部参数都将and在一块儿
字段类 | 说明 |
---|---|
AutoField | 自增的整数字段,若是不指定Django会为模型类型自动增长主键字段 |
BooleanField | 布尔值字段,True和False,对应表单控件CheckboxInput |
NullBooleanField | 比BooleanField 多一个空值 |
CharField | 字符串,max_length 设定字符串长度,表单控件TextInput |
TextField | 大文本字段,通常超过4000个字符使用,对应表单控件Textarea |
IntegerField | 整数字段 |
BigIntegerField | 更大整数字段,8字节 |
DecimalField | 使用Python的Decimal实例表示十进制的浮点数,max_digits 总位数,decimal_places 小数点后的位数 |
FloatField | python中的Float实例表示的浮点数 |
DateField | 使用python的datetime.date 实例表示的日期,auto_now=False每次修改对象自动设置为当前时间,auto_now_add=False对象第一次建立时自动设置为当前时间,auto_now_add,auto_now,default互斥,对应控件为TextInput,关联了一个js编写的日历控件 |
TimeField | 使用python的datetime.time实例表示时间,参数同上 |
DateTimeField | 使用python的datetime.datetime实例表示的时间,参数同上 |
FileField | 一个上传文件的字段 |
ImageField | 继承了FileField 的全部属性和方法,可是对上传文件进行校验,确保是一个有效的图片 |
值 | 说明 |
---|---|
db_column | 表中字段的名称,若是未指定,则使用属性名 |
primary_key | 是否为主键 |
unique | 是不是惟一 |
default | 缺省值,这个缺省值不是数据库字段的缺省值,而是新对象产生的是够被填入的缺省值 |
null | 表的字段是否能够为null,默认为False |
db_index | 字段是否有索引 |
类 | 说明 |
---|---|
ForeignKey | 外键,表示一对多 ForeignKey('production.Manufacturer')自关联 ForeiginKey('self') |
ManyToMaryField | 表示多对多 |
OneToOneField | 表示一对一 |
一对多时,自动建立会增长_id后缀。
从一访问多,使用 对象.小写模型类_set
从一访问一,使用 对象.小写模型类
访问 id 对象.属性_id
基类 models.Model
表名不指定默认使用<appname>_<model_name>,使用Meta类修改表名
相关代码以下
from django.db import models # Create your models here. class User(models.Model): class Meta: db_table='user' # 定义数据库表名 id = models.AutoField(primary_key=True) # 定义主键自增字段 name=models.CharField(max_length=48,null=False) # 定义name为浮点型,且其不能为空 email=models.CharField(max_length=64,unique=True,null=False) # 定义邮件为浮点类型,且其必须惟一,不能为空 password=models.CharField(max_length=128,null=False) # 定义密码类型,其为浮点数,且不能为空 def __repr__(self): return '<user {} {}>'.format(self.id,self.name) __str__=__repr__
迁移 migration
迁移:从模型定义生成数据库的表
1 在项目根目录执行下面文件生成迁移文件
python manage.py makemigrations
结果以下
修改过Model类,还须要调用makemigrations,而后migrate,迁移文件的序号会增长
注意:迁移的应用必须在settings.py 的 INSTALLED_APPS 中注册
2 在项目的根目录执行迁移生成数据库的表
python manage.py migrate
结果以下