Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
本文将以下方面带大家全面了解Django框架,笔者使用的版本为1.10.
流程
基本配置
路由系统
视图view
模板
Model
中间件
Form
认证系统
CSRF
分页
Cookie
Seesion
缓存
序列化
信号
admin
一、 Django流程介绍
MVC是众所周知的模式,即:将应用程序分解成三个组成部分:model(模型),view(视图),和 controller(控制 器)。其中:
M——管理应用程序的状态(通常存储到数据库中),并约束改变状态的行为(或者叫做“业务规则”)。
C——接受外部用户的操作,根据操作访问模型获取数据,并调用“视图”显示这些数据。控制器是将“模型”和“视图”隔离,并成为二者之间的联系纽带。
V——负责把数据格式化后呈现给用户。
Django也是一个MVC框架。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式:
M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。
T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。
二、 Django 基本配置
- 创建django程序
终端命令:django-admin startproject sitename (在当前目录下创建一个Django程序)
IDE创建Django程序时,本质上都是自动执行上述命令
其他常用命令:
python manage.py runserver ip:port (启动服务器,默认ip和端口为http://127.0.0.1:8000/)
python manage.py startapp appname (新建 app)
python manage.py syncdb (同步数据库命令,Django 1.7及以上版本需要用以下的命令)
python manage.py makemigrations (显示并记录所有数据的改动)
python manage.py migrate (将改动更新到数据库)
python manage.py createsuperuser (创建超级管理员)
python manage.py dbshell (数据库命令行)
python manage.py (查看命令列表)
-
程序目录
-
配置文件
a、数据库
支持SQLite 3(默认)、PostgreSQL 、MySQL、Oracle数据库的操作
具体配置
Django框架对于开发者而言高度透明化,对于不同数据库的具体使用方法是一致的,改变数据库类型只需要变动上述配置即可。
想要了解更多请戳这里
b、静态文件添加
settings配置
三、 Django 路由系统
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的加载是从配置文件中开始。
参数说明:
一个正则表达式字符串
一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
可选的要传递给视图函数的默认参数(字典形式)
一个可选的name参数
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
说明:
要捕获从URL中的值,用括号括起来,会当参数传入 views 视图。
没有必要添加一个斜线,因为每个URL都有。例如,它articles不是/articles。
在’r’前面的每个正则表达式字符串中是可选的,但建议。它告诉Python字符串是“原始” -没有什么字符串中应该进行转义。
请求示例:
一个请求 /articles/2005/03/ 会匹配上面列表中的第三条. Django 会调用函数 views.month_archive(request, ‘2005’, ‘03’).
/articles/2005/3/ 不会匹配上面列表中的任何条目, 因为第三条的月份需要二位数字.
/articles/2003/ 会匹配上第一条而不是第二条,因为匹配是按照从上到下顺序而进行的, Django 会调用函数 views.special_case_2003(request)
/articles/2003 不会匹配上面列表中的任何条目, 因为每个URL应该以 / 结尾.
/articles/2003/03/03/ 会匹配上最后一条. Django 会调用函数 views.article_detail(request, ‘2003’, ‘03’, ‘03’).
- 命名组(Named groups)
在上面的简单例子中,并没有使用正则表达式分组,在更高级的用法中,很有可能使用正则分组来匹配URL并且将分组值通过参数传递给view函数。
在Python的正则表达式中,分组的语法是 (?Ppattern), name表示分组名,pattern表示一些匹配正则.
正则知识
import re
ret=re.search(’(?P\d{3})/(?P\w{3})’,‘weeew34ttt123/ooo’)
print(ret.group())
print(ret.group(‘id’))
print(ret.group(‘name’))
123/ooo
123
ooo
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
For example:
A request to /articles/2005/03/ 会调用函数 views.month_archive(request, year=‘2005’,month=‘03’), 而不是 views.month_archive(request, ‘2005’, ‘03’).
A request to /articles/2003/03/03/ 会调用函数 views.article_detail(request, year=‘2003’,month=‘03’, day=‘03’).
常见写法实例:
- 二级路由(Including)
那如果映射 url 太多怎么办,全写一个在 urlpatterns 显得繁琐,so 二级路由应用而生
from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
url(r'^reports/$', credit_views.report),
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)),
]
在上面这个例子中,如果请求url为 /credit/reports/ 则会调用函数 credit_views.report().
使用二级路由也可以减少代码冗余,使代码更加简洁易懂
- View Code
- 添加额外的参数
URLconfs 有一个钩子可以让你加入一些额外的参数到view函数中.
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在上面的例子中,如果一个请求为 /blog/2005/, Django 将会调用函数l views.year_archive(request, year=‘2005’,foo=‘bar’).
需要注意的是,当你加上参数时,对应函数views.year_archive必须加上一个参数,参数名也必须命名为 foo,如下:
def year_archive(request, foo):
print(foo)
return render(request, 'index.html')
- 别名的使用
1
url(r’^index’,views.index,name=‘bieming’)
url中还支持name参数的配置,如果配置了name属性,在模板的文件中就可以使用name值来代替相应的url值.
我们来看一个例子:
name的应用
- 指定view的默认配置
URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
View (in blog/views.py)
def page(request, num=“1”):
# Output the appropriate page of blog entries, according to num.
...
在上述的例子中,两个 URL 模式指向同一个视图 views.page 但第一图案不捕获从 URL 任何东西。如果第一个模式匹配,该 page() 函数将使用它的默认参数 num,“1”。如果第二图案相匹配时, page()将使用任何 num 值由正则表达式捕获。
四、 Django Views(视图函数)
http请求中产生两个核心对象:
http请求:HttpRequest对象
http响应:HttpResponse对象
- HttpRequest对象
当请求一个页面时,Django 创建一个 HttpRequest对象包含原数据的请求。然后 Django 加载适当的视图,通过 HttpRequest作为视图函数的第一个参数。每个视图负责返回一个HttpResponse目标。
复制代码
path: 请求页面的全路径,不包括域名
method: 请求中使用的HTTP方法的字符串表示。全大写表示。例如
if req.method=="GET":
do_something()
elseif req.method=="POST":
do_something_else()
GET: 包含所有HTTP GET参数的类字典对象
POST: 包含所有HTTP POST参数的类字典对象
服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过
HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用
if req.POST来判断是否使用了HTTP POST 方法;应该使用 if req.method=="POST"
COOKIES: 包含所有cookies的标准Python字典对象;keys和values都是字符串。
FILES: 包含所有上传文件的类字典对象;FILES中的每一个Key都是标签中
name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:
filename: 上传文件名,用字符串表示
content_type: 上传文件的Content Type
content: 上传文件的原始内容
user: 是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前
没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你
可以通过user的is_authenticated()方法来辨别用户是否登陆:
if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
时该属性才可用
session: 唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。
META: 一个标准的Python字典包含所有可用的HTTP头。可用标题取决于客户端和服务器,但这里是一些例子:
CONTENT_LENGTH – 请求体的长度(一个字符串)。
CONTENT_TYPE – 请求体的类型。
HTTP_ACCEPT - 为响应–可以接受的内容类型。
HTTP_ACCEPT_ENCODING – 接受编码的响应
HTTP_ACCEPT_LANGUAGE – 接受语言的反应
HTTP_HOST – 客户端发送的HTTP主机头。
HTTP_REFERER – 参考页面
HTTP_USER_AGENT – 客户端的用户代理字符串。
QUERY_STRING – 查询字符串,作为一个单一的(分析的)字符串。
REMOTE_ADDR – 客户端的IP地址
REMOTE_HOST – 客户端的主机名
REMOTE_USER – 用户通过Web服务器的身份验证。
REQUEST_METHOD – 字符串,如"GET"或"POST"
SERVER_NAME – 服务器的主机名
SERVER_PORT – 服务器的端口(一个字符串)。
复制代码
- HttpResponse对象
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
在HttpResponse对象上扩展的常用方法:
页面渲染:render(推荐),render_to_response,
页面跳转:redirect
locals: 可以直接将对应视图函数中所有的变量传给模板
值得注意的是对于页面渲染的方法中,render和render_to_response使用方法和功能类似,但是render功能更为强大,推荐使用
- render()
render(request, template_name, context=None, content_type=None, status=None, using=None)[source]
结合给定的模板与一个给定的上下文,返回一个字典HttpResponse在渲染文本对象
所需的参数
template_name 一个模板的使用或模板序列名称全称。如果序列是给定的,存在于第一个模板将被使用。
可选参数
context 一组字典的值添加到模板中。默认情况下,这是一个空的字典。
content_type MIME类型用于生成文档。
status 为响应状态代码。默认值为200
using 这个名字一个模板引擎的使用将模板。
复制代码
from django.shortcuts import render
def my_view(request):
# View code here…
return render(request, ‘myapp/index.html’, {
‘foo’: ‘bar’,
}, content_type=‘application/xhtml+xml’)
复制代码
五、 模板
- 模板的执行
模版的创建过程,对于模版,其实就是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户。
示例
- 模板语言
模板中也有自己的语言,该语言可以实现数据展示
{{ item }}
{% for item in item_list %} {{ item }} {% endfor %}
forloop.counter
forloop.first
forloop.last
{% if ordered_warranty %} {% else %} {% endif %}
母板:{% block title %}{% endblock %}
子板:{% extends “base.html” %}
{% block title %}{% endblock %}
帮助方法:
{{ item.event_start|date:“Y-m-d H:i:s”}}
{{ bio|truncatewords:“30” }}
{{ my_list|first|upper }}
{{ name|lower }}
小知识点:在模板语言中字典数据类型的取值是通过dict.xxx而不是dict[xxx]
- 自定义标签
因为在模板语言中不能够做运算等一些稍显复杂的操作,所以在Django中提供了两种自定制标签,一种是simple_tag,一种是filter。
simple_tag: 任意传递参数,但是不能用作布尔判断
filter: 最多只能传递二个参数,可以用作布尔判断
在这里着重介绍simple_tag类型,filter的实现类似
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
复制代码
#!/usr/bin/env python
#coding:utf-8
from django import template
from django.utils.safestring import mark_safe
from django.template.base import resolve_variable, Node, TemplateSyntaxError
register = template.Library()
@register.simple_tag
def my_simple_time(v1,v2,v3):
return v1 + v2 + v3
@register.simple_tag
def my_input(id,arg):
result = “” %(id,arg,)
return mark_safe(result)
复制代码
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%}
{% my_input ‘id_username’ ‘hide’%}
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
示例
更多见文档:https://docs.djangoproject.com/en/1.10/ref/templates/language/
六、 Model
Django提供了一个抽象层(“Model”)来构建和管理Web应用程序的数据。
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
关系对象映射(Object Relational Mapping,简称ORM)。
- 创建表
a、基本结构
from django.db import models
class userinfo(models.Model):
name = models.CharField(max_length=30)
email = models.EmailField()
memo = models.TextField()
复制代码
1、null=True
数据库中字段是否可以为空
2、blank=True
django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
auto_now 自动创建—无论添加或修改,都是当前操作的时间
auto_now_add 自动创建—永远是创建时的时间
5、choices
GENDER_CHOICE = (
(u’M’, u’Male’),
(u’F’, u’Female’),
)
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default 默认值
8、verbose_name Admin中字段的显示名称
9、name|db_column 数据库中的字段名称
10、unique=True 不允许重复
11、db_index = True 数据库索引
12、editable=True 在Admin里是否可编辑
13、error_messages=None 错误提示
14、auto_created=False 自动创建
15、help_text 在Admin中提示帮助信息
16、validators=[]
17、upload-to
复制代码
复制代码
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField 字符串字段
必须 max_length 参数
3、models.BooleanField 布尔类型=tinyint(1)
不能为空,Blank=True
4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar
继承CharField,所以必须 max_lenght 参数
5、models.DateField 日期类型 date
对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField 日期类型 datetime
同DateField的参数
7、models.Decimal 十进制小数类型 = decimal
必须指定整数位max_digits和小数位decimal_places
8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
对字符串进行正则表达式
9、models.FloatField 浮点类型 = double
10、models.IntegerField 整形
11、models.BigIntegerField 长整形
integer_field_ranges = {
‘SmallIntegerField’: (-32768, 32767),
‘IntegerField’: (-2147483648, 2147483647),
‘BigIntegerField’: (-9223372036854775808, 9223372036854775807),
‘PositiveSmallIntegerField’: (0, 32767),
‘PositiveIntegerField’: (0, 2147483647),
}
12、models.IPAddressField 字符串类型(ip4正则表达式)
13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
参数protocol可以是:both、ipv4、ipv6
验证时,会根据设置报错
14、models.NullBooleanField 允许为空的布尔类型
15、models.PositiveIntegerFiel 正Integer
16、models.PositiveSmallIntegerField 正smallInteger
17、models.SlugField 减号、下划线、字母、数字
18、models.SmallIntegerField 数字
数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField 字符串=longtext
20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField 字符串,地址正则表达式
22、models.BinaryField 二进制
23、models.ImageField 图片
24、models.FilePathField 文件
复制代码
复制代码
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = “table_name”
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
复制代码
复制代码
1.触发Model中的验证和错误提示有两种方式:
a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
b. 调用Model对象的 clean_fields 方法,如:
# models.py
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={'invalid': '格式错了.'})
# views.py
def index(request):
obj = models.UserInfo(username='11234', email='uu')
try:
print(obj.clean_fields())
except Exception as e:
print(e)
return HttpResponse('ok')
# Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
2.Admin中修改错误提示
# admin.py
from django.contrib import admin
from model_club import models
from django import forms
class UserInfoForm(forms.ModelForm):
username = forms.CharField(error_messages={'required': '用户名不能为空.'})
email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})
class Meta:
model = models.UserInfo
# fields = ('username',)
fields = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)
复制代码
b、连表结构
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
字段以及参数
- 操作表
a、基本操作
基本操作
b、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来
复制代码
获取个数
#
# models.Tb1.objects.filter(name='seven').count()
# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
# in
#
# models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
# isnull
# Entry.objects.filter(pub_date__isnull=True)
# contains
#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
# models.Tb1.objects.exclude(name__icontains="ven")
# range
#
# models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
# 其他类似
#
# startswith,istartswith, endswith, iendswith,
# order by
#
# models.Tb1.objects.filter(name='seven').order_by('id') # asc
# models.Tb1.objects.filter(name='seven').order_by('-id') # desc
# group by
#
# from django.db.models import Count, Min, Max, Sum
# models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
# limit 、offset
#
# models.Tb1.objects.all()[10:20]
# regex正则匹配,iregex 不区分大小写
#
# Entry.objects.get(title__regex=r'^(An?|The) +')
# Entry.objects.get(title__iregex=r'^(an?|the) +')
# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)
# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)
# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)
# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
# hour
#
# Event.objects.filter(timestamp__hour=23)
# Event.objects.filter(time__hour=5)
# Event.objects.filter(timestamp__hour__gte=12)
# minute
#
# Event.objects.filter(timestamp__minute=29)
# Event.objects.filter(time__minute=46)
# Event.objects.filter(timestamp__minute__gte=29)
# second
#
# Event.objects.filter(timestamp__second=31)
# Event.objects.filter(time__second=2)
# Event.objects.filter(timestamp__second__gte=31)
复制代码
c、其他操作
复制代码
extra
#
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
# Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
# Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
# F
#
# from django.db.models import F
# models.Tb1.objects.update(num=F('num')+1)
# Q
#
# 方式一:
# Q(nid__gt=10)
# Q(nid=8) | Q(nid__gt=10)
# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
# 方式二:
# con = Q()
# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 10))
# q1.children.append(('id', 9))
# q2 = Q()
# q2.connector = 'OR'
# q2.children.append(('c1', 1))
# q2.children.append(('c1', 10))
# q2.children.append(('c1', 9))
# con.add(q1, 'AND')
# con.add(q2, 'AND')
#
# models.Tb1.objects.filter(con)
# 执行原生SQL
#
# from django.db import connection, connections
# cursor = connection.cursor() # cursor = connections['default'].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()
复制代码
d、连表操作(了不起的双下划线)
利用双下划线和 _set 将表之间的操作连接起来
表结构实例
一对一操作
一对多
多对多操作
扩展:
a、自定义上传
复制代码
def upload_file(request):
if request.method == “POST”:
obj = request.FILES.get(‘fafafa’)
f = open(obj.name, ‘wb’)
for chunk in obj.chunks():
f.write(chunk)
f.close()
return render(request, ‘file.html’)
复制代码
b、Form上传文件实例
复制代码
HTML
<form method="post" action="/view1/" enctype="multipart/form-data">
<input type="file" name="ExcelFile" id="id_ExcelFile" />
<input type="submit" value="提交" />
</form>
Form
class FileForm(forms.Form):
ExcelFile = forms.FileField()
Models
from django.db import models
class UploadFile(models.Model):
userid = models.CharField(max_length = 30)
file = models.FileField(upload_to = ‘./upload/’)
date = models.DateTimeField(auto_now_add=True)
Views
def UploadFile(request):
uf = AssetForm.FileForm(request.POST,request.FILES)
if uf.is_valid():
upload = models.UploadFile()
upload.userid = 1
upload.file = uf.cleaned_data[‘ExcelFile’]
upload.save()
print upload.file
复制代码
c、ajax上传文件实例
复制代码
复制代码
class FileForm(forms.Form):
ExcelFile = forms.FileField()
复制代码
from django.db import models
class UploadFile(models.Model):
userid = models.CharField(max_length = 30)
file = models.FileField(upload_to = ‘./upload/’)
date = models.DateTimeField(auto_now_add=True)
复制代码
复制代码
from study1 import forms
def UploadFile(request):
uf = AssetForm.FileForm(request.POST,request.FILES)
if uf.is_valid():
upload = models.UploadFile()
upload.userid = 1
upload.file = uf.cleaned_data[‘ExcelFile’]
upload.save()
print upload.file
return render(request, ‘file.html’, locals())
复制代码
七、中间件(MiddleWare)
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。
与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类
中间件中可以定义五个方法,分别是:
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
分析源码得知前二个方法是从前往后执行的,后三个方法是从后往前执行的
所以前两个方法是请求进来时要穿越的,而后三个方法是请求出去时要穿越的
一张图告诉你中间件的运行流程
自定义中间件
1、创建中间件类
class Middle_Test(object):
def process_request(self,request):
pass
def process_view(self, request, callback, callback_args, callback_kwargs):
i =1
pass
def process_exception(self, request, exception):
pass
def process_response(self, request, response):
return response
2、注册中间件
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'sparks.middleware.auth.Middle_Test',
)
八、 Form
django中的Form一般有两种功能:
输入html
验证用户输入
Form
示例
利用Form还可以自动生成前端的input标签:
form.py
views.py
form1.html
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
ModelForm
九、 认证系统(auth)
auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.
在INSTALLED_APPS中添加’django.contrib.auth’使用该APP, auth模块默认启用.
model
from django.contrib.auth.models import User
数据库中该表名为auth_user.
CREATE TABLE “auth_user” (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"password" varchar(128) NOT NULL, "last_login" datetime NULL,
"is_superuser" bool NOT NULL,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL,
"email" varchar(254) NOT NULL,
"is_staff" bool NOT NULL,
"is_active" bool NOT NULL,
"date_joined" datetime NOT NULL,
"username" varchar(30) NOT NULL UNIQUE
)
新建用户
user = User.objects.create_user(username, email, password)
user.save()
不存储用户密码明文而是存储一个Hash值
认证用户
复制代码
复制代码
from django.contrib.auth import authenticate
user = authenticate(username=username, password=password)
认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None.
该方法不检查is_active标志位.
复制代码
复制代码
修改密码
复制代码
复制代码
user.set_password(new_password)
以下实例为先认证通过后才可以修改密码
user = auth.authenticate(username=username, password=old_password)
if user is not None:
user.set_password(new_password)
user.save()
复制代码
复制代码
登录
复制代码
复制代码
from django.contrib.auth import login
login向session中添加SESSION_KEY, 便于对用户进行跟踪:
‘login(request, user)’
login不进行认证,也不检查is_active标志位
实例
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
复制代码
复制代码
退出登录
复制代码
复制代码
logout会移除request中的user信息, 并刷新session
from django.contrib.auth import logout
def logout_view(request):
logout(request)
复制代码
复制代码
只允许登录的用户访问
@login_required修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置.
若未指定login_url参数, 则重定向到settings.LOGIN_URL
复制代码
复制代码
from django.contrib.auth.decorators import login_required
@login_required(login_url=’/accounts/login/’)
def userinfo(request):
…
settings 配置
LOGIN_URL = ‘/index/’
views
@login_required
def userinfo(request):
…
复制代码
复制代码
十、 跨站请求伪造(csrf)
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
在Django1.10中,为了防止BREACH攻击,对cookie-form类型的csrf做了一点改进,即在cookie和form中的token值是不相同的
应用
1、普通表单
1
2
3
4
5
veiw中设置返回值:
return render(request, 'xxx.html', data)
html中设置Token:
{% csrf_token %}
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
text.html
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
十一、 分页
- Django内置分页
views.py
Html
扩展内置分页:views.py
扩展内置分页:Html
- 自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页…)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页…)
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出,总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
分页实例
总结,分页时需要做三件事:
创建处理分页数据的类
根据分页数据获取数据
输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
十二、 Cookie
- 获取Cookie:
1
2
3
4
5
6
request.COOKIES[‘key’]
request.get_signed_cookie(key, default=RAISE_ERROR, salt=’’, max_age=None)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间
- 设置Cookie:
1
2
3
4
5
6
7
8
9
10
11
12
13
rep = HttpResponse(…) 或 rep = render(request, …)
rep.set_cookie(key,value,…)
rep.set_signed_cookie(key,value,salt=‘加密盐’,…)
参数:
key, 键
value='', 值
max_age=None, 超时时间
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
secure=False, https传输
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
1
2
$.cookie(“list_pager_num”, 30,{ path: ‘/’ });
十三、 Session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
数据库(默认)
缓存
文件
缓存+数据库
加密cookie
1、数据库Session
View Code
2、缓存Session
View Code
3、文件Session
View Code
4、缓存+数据库Session
View Code
5、加密cookie Session
View Code
跟数据库的操作一样,在Django中不同缓存方式的使用方法是一致的,想要改变缓存的类型只需要改变上述相应配置即可。
更多参考:猛击这里 和 猛击这里
扩展:Session用户验证(装饰器)
1
2
3
4
5
6
7
def login(func):
def wrap(request, *args, **kwargs):
# 如果未登陆,跳转到指定页面
if request.path == '/test/':
return redirect('http://www.baidu.com')
return func(request, *args, **kwargs)
return wrap
十四、 缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
开发调试
内存
文件
数据库
Memcache缓存(python-memcached模块)
Memcache缓存(pylibmc模块)
和数据库类似,缓存的具体操作都是一样的,使用不同的方式只需要将配置改掉即可
1、配置
a、开发调试
View Code
b、内存
View Code
c、文件
View Code
d、数据库
View Code
e、Memcache缓存(python-memcached模块)
View Code
f、Memcache缓存(pylibmc模块)
View Code
2、应用
a. 全站使用
View Code
b. 单独视图缓存
View Code
c、局部视图使用
View Code
注:如果出现多个url匹配同一个view函数的情况,缓存机制会根据每一个不同的url做单独的缓存
更多:猛击这里
十五、 序列化
关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。
- serializers
from django.core import serializers
ret = models.BookType.objects.all()
data = serializers.serialize(“json”, ret)
- json.dumps
import json
#ret = models.BookType.objects.all().values(‘caption’)
ret = models.BookType.objects.all().values_list(‘caption’)
ret=list(ret)
result = json.dumps(ret)
由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:
自定义示例
十六、 信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
Model signals
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
View Code
2、自定义信号
a. 定义并注册信号
自定制信号
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=[“toppings”, “size”])
def callback(sender, **kwargs):
print("self-define")
print(sender, kwargs)
pizza_done.connect(callback)
b. 触发信号
from 路径 import pizza_done
pizza_done.send(sender=‘seven’,toppings=123, size=456)
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。
更多:猛击这里
十七、admin
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
创建后台管理员
配置url
注册和配置django admin后台管理页面
注:不建议新手经常使用admin,会形成依赖,核心的是model模块的操作!
1、创建后台管理员
python manage.py createsuperuser
2、配置后台管理url(默认已配)
url(r’^admin/’, include(admin.site.urls))
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
View Code
b、设置数据表名称
View Code
c、打开表之后,设定默认显示,需要在model中作如下配置
View Code
d、为数据表添加搜索功能
View Code
e、添加快速过滤
View Code