http://www.cnblogs.com/wupeiqi/articles/5237704.html
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/yuanchenqi/articles/5786089.html
基本配置
一 常用命令
django-admin startproject sitename
python manage.py runserver 0.0.0.0
python manage.py startapp appname
python manage.py syncdb
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
二、数据库配置(mysql)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '',
'PORT': '',
}
}
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
# 如下设置放置的与project同名的配置的 __init__.py文件中
import pymysql
pymysql.install_as_MySQLdb()
三、配置模板和静态文件
TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates'),
)
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), ) # 特有的静态文件夹放在app里面, # 模板里面使用静态文件
最后记得在setting里面注册app
Django流程
一、MTV模式
MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起。模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求。
Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表:
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
路由系统
URL模式以及要为该URL模式调用的视图函数之间的映射表,每个路由对应一个view中的函数,对于这个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/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
# 路由分发
url(r'^contact/', include('django_website.contact.urls')),
# 传给视图的默认参数,对应的视图函数也必须加上同名的参数
url(r'^blog/(?P[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
#name参数
url(r'^index',views.index,name='bieming'),
]
常见写法实例
urlpatterns = [
url(r'car', views.car, {'name': 'jaon'},),
url(r'index', views.index, name='alias_login',),
# url(r'index55555', views.index, name='alias_login',),
]
def car(request, name):
return HttpResponse('car'+name)
def index(request,):
if request.method == 'POST':
username = request.POST.get('username')
print(username)
if username == 'jason':
return HttpResponse('ok')
else:
return HttpResponse('error')
return render(request, 'login.html')
Title
视图函数
1、HttpRequest对象的属性:
# 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支持时该属性才可用。
HttpRequest对象的方法:get_full_path(), 比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
2、HttpResponse对象:
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
HttpResponse类在django.http.HttpResponse
在HttpResponse对象上扩展的常用方法:页面渲染:render,render_to_response,
页面跳转:redirect
locals: 可以直接将函数中所有的变量传给模板
django的ORM
这里先创建几张表,分别是一对多和多对多,其中一对一就是一对多的时候外键唯一
from django.db import models
# Create your models here.
class UserType(models.Model):
nid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
user = models.CharField(max_length=16)
pwd = models.CharField(max_length=16)
email = models.EmailField()
userType = models.ForeignKey(UserType)
class Group(models.Model):
name = models.CharField(max_length=16)
h2g = models.ManyToManyField('Host')
class Host(models.Model):
hostname = models.CharField(max_length=16)
ip = models.CharField(max_length=16)
下面来看一下表的增删改查的简单操作
# 第一种方式创建
# usertype = models.UserType(caption='管理员')
# usertype.save()
# 第二种方式创建
# models.UserType.objects.create(caption='普通用户')
# 第三种
# userTypeDict = {'caption': '协管员'}
# models.UserType.objects.create(**userTypeDict)
# 带外键添加数据库 推荐使用
# userInfoDict = {
# 'user': 'jason',
# 'email': '[email protected]',
# 'pwd': '123',
# 'userType_id': 2,
# }
# userInfoDict = {
# 'user': 'jason2',
# 'email': '[email protected]',
# 'pwd': '123',
# 'userType': models.UserType.objects.filter(nid=2).first(),
# }
# models.UserInfo.objects.create(**userInfoDict)
# 删除
# models.UserType.objects.filter(nid=3).delete()
# 修改
# models.UserType.objects.filter(nid=1).update(caption='超级管理员')
# 查询 查询结果是QuerySet
# ret = models.UserType.objects.all() # select会获取所有的映射
# print(type(ret), ret, ret.query) # ret 里面保存的是对象
# ret = models.UserType.objects.all().values('nid') # 获取指定映射
# print(type(ret), ret, ret.query) # ret 里面保存的是字典
# ret = models.UserType.objects.all().values_list('nid') # 获取指定映射
# print(type(ret), ret, ret.query) # ret 里面保存的是元祖
再来看一下一对多连表查找操作
# 连表 双下划线使用,注意什么情况下使用 表名_set 什么情况下使用 表名__字段
# (表名_set 获取QuerySet对象) (表名__字段,查找过滤映射的时候用)
# 正向查找,再多的一方查找一的一方
# ret = models.UserInfo.objects.all().values('user', 'userType__caption')
# print(ret)
# ret = models.UserInfo.objects.filter(userType__caption="普通用户").values('user', 'userType__caption')
# print(ret)
# 反向查找 在一的一方查找多的一方
# 在获取了一对多中一那一方的对象之后,要获取多的那一方对象使用反向表名_set
# ret = models.UserType.objects.filter(caption='普通用户').first()
# print(ret.nid, ret.userinfo_set, ret.userinfo_set.all(), ret.userinfo_set.all()[0].user)
# 直接在一对多一那一方使用查找或者过滤映射的时候使用反向表名__字段
# ret = models.UserType.objects.all().values('caption', 'userinfo__user')
# print(ret)
最后看一下多对多连表查找操作
'''
创建表:
直接使用m2m
自已定义第三张表
自已定义第三张表 + m2m(through) 可以通过through参数来指明存在的表
直接使用m2m
--- 获取值
add添加
remove删除(关系表),filter.delete()(关系表+..)
set设置(添加、删除)
get_or_create
update_or_create
自已定义第三张表 + m2m + through
--关系表只能获取值 filter,all...
通过第三张表进行操作
'''
'''
# 直接使用
class Host(models.Model):
hid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32)
ip = models.CharField(max_length=32)
# h2g = models.ManyToManyField('Group')
class Group(models.Model):
gid = models.AutoField(primary_key=True)
name = models.CharField(max_length=16)
h2g = models.ManyToManyField('Host')
# 自定义第三张表
# class Host(models.Model):
# hid = models.AutoField(primary_key=True)
# hostname = models.CharField(max_length=32)
# ip = models.CharField(max_length=32)
# # h2g = models.ManyToManyField('Group', through='HostToGroup')
# class Group(models.Model):
# gid = models.AutoField(primary_key=True)
# name = models.CharField(max_length=16)
#
# h2g = models.ManyToManyField('Host')
#
# class HostToGroup(models.Model):
# hgid = models.AutoField(primary_key=True)
# host_id = models.ForeignKey('Host')
# group_id = models.ForeignKey('Group')
# status = models.IntegerField()
# class Meta:
# # index_together = ("host_id",'goup_id') 组合索引
# unique_together = [
# ('host_id', 'group_id'), 组合唯一索引
# ]
'''
# 将多台机器分给一组 正向
# obj = models.Group.objects.get(id=1)
# hosts = models.Host.objects.filter(id__gt=2)
# obj.h2g.add(*hosts)
# host = models.Host.objects.get(id=2)
# obj.h2g.add(host)
# 给多个组分一台机器 反向
# h = models.Host.objects.get(id=1)
# h.group_set.add(*models.Group.objects.filter(id__gt=2))
# h.group_set.add(2) # 可以直接添加id或对象
# h.group_set.remove(*models.Group.objects.filter(id__gt=3)) # 只删除关系表
# h.group_set.filter(id__gt=2).delete() # group_id>2 的关系表删除了,相应的group表数据也被删除了
# h.group_set.set(models.Group.objects.filter(id__gt=1), clear=True) #大于1的全部清除在添加
# h.group_set.set(models.Group.objects.filter(id__gt=2)) # 大于2 以前存在的不清除,不存在的添加
# h.group_set.set(models.Group.objects.filter(id__gt=4)) # 小于5的被清除
# r = h.group_set.update_or_create(name='人事部') # 两张表都不存在,先在group表创建在添加到关系表中去
# print(r)
# r = h.group_set.update_or_create(name='pm') # 和上面的效果一样,为什么
# h.group_set.get_or_create(name='te') # 和上面的效果一样
具体操作
补充:
一次插入多条数据
author_list = []
for i in range(7):
name = 'alex' + str(i)
age = i
author = models.Author(name=name, age=age)
author_list.append(author)
models.Author.objects.bulk_create(author_list)
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 文件
更多字段
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
更多参数
# 获取个数
#
# models.Tb1.objects.filter(name='seven').count()
# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__lt=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
# 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
# limit 、offset
#
# models.Tb1.objects.all()[10:20]
# 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"
双下画线操作
示例、用Q进行简单搜索
# F 使用查询条件的值
#
# from django.db.models import F
# models.Tb1.objects.update(num=F('num')+1)
# Q 构建搜索条件
from django.db.models import Q
# 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)
#
# from django.db import connection
# cursor = connection.cursor()
# cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
# row = cursor.fetchone()
F和Q
Title
+
前端index
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
class BookType(models.Model):
caption = models.CharField(max_length=32)
class Book(models.Model):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=10, decimal_places=2)
pubdate = models.DateField()
authors = models.ManyToManyField(Author)
book_type = models.ForeignKey(BookType)
后端models
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
import json
def test(request):
# models.BookType.objects.create(caption='技术')
# models.BookType.objects.create(caption='文学')
# models.BookType.objects.create(caption='动漫')
# models.BookType.objects.create(caption='男人装')
# models.Book.objects.create(name='文艺复兴',pages='100',price='40',pubdate='1992-11-2',book_type_id='1')
# models.Book.objects.create(name='解密',pages='80',price='10', pubdate='2016-6-10',book_type_id='2')
# models.Book.objects.create(name='刀锋',pages='50',price='3', pubdate='2014-02-16',book_type_id='2')
# models.Book.objects.create(name='查令十字路84号',pages='260',price='40',pubdate='1999-10-12',book_type_id='3')
# models.Book.objects.create(name='红楼',pages='1000',price='500', pubdate='1760-1-1',book_type_id='3')
# models.Book.objects.create(name='将夜',pages='2000',price='300', pubdate='2010-3-3',book_type_id='1')
# models.Book.objects.create(name='mysql从删库到跑路',pages='20',price='10',pubdate='1998-9-2',book_type_id='4')
# models.Book.objects.create(name='马克思主义',pages='50',price='100',pubdate='1937-3-3',book_type_id='2')
return HttpResponse('ok')
import json
from datetime import date
from datetime import datetime
from decimal import Decimal
class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field, datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return field.strftime('%Y-%m-%d')
elif isinstance(field, Decimal):
return str(field)
else:
return json.JSONEncoder.default(self, field)
def index(request):
if request.method == 'POST':
ret = {'status': False, 'message': '', 'data':None}
try:
post_data = request.POST.get('post_data',None)
post_data_dict = json.loads(post_data)
print(post_data_dict)
# {'name': ['11', 'sdf'],'price': ['11', 'sdf']}
# 构造搜索条件
from django.db.models import Q
con = Q()
for k,v in post_data_dict.items():
q = Q()
q.connector = 'OR'
for item in v:
q.children.append((k, item))
con.add(q, 'AND')
"""
ret = models.Book.objects.filter(con)
print(ret) # queryset,[对象]
from django.core import serializers
data = serializers.serialize("json", ret) # 这种方法获取到的图书类型是id不是book_type__caption
print(type(data),data)
# 字符串
"""
"""
#ret = models.Book.objects.filter(con).values('name','book_type__caption')
ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption')
print(ret,type(ret))
li = list(ret)
data = json.dumps(li)
print(data,type(data))
"""
result = models.Book.objects.filter(con).values('name','price','pubdate','book_type__caption')
# ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption')
li = list(result)
ret['status'] = True
ret['data'] = li
except Exception as e:
ret['message'] = str(e)
ret_str = json.dumps(ret, cls=JsonCustomEncoder)
return HttpResponse(ret_str)
return render(request, 'index.html')
后端view
form验证
#!/usr/bin/env python
# coding=utf-8
from django import forms
class Forml(forms.Form):
# username = forms.CharField()
# pwd = forms.CharField()
user = forms.CharField(
widget=forms.TextInput(attrs={
'class': 'c1',
}),
error_messages={
'required': '用户名不能为空',
},
)
pwd = forms.CharField(max_length=4, min_length=2)
# email = forms.EmailField(
# error_messages={
# 'required': '邮箱不能为空',
# 'invalid': '邮箱格式错误',
# }
# )
email = forms.EmailField(
error_messages={
'required': '邮箱不能为空',
'invalid': '邮箱格式错误'
}
)
memo = forms.CharField(
widget=forms.Textarea()
)
# 自定义
user_type_choice = (
(0, '普通用户'),
(1, '高级用户'),
)
# 如果从数据库查找,则Forml里面定义的静态字段只会执行一次
# user_type_choice = models.BookType.objects.values_list('id', 'caption')
book_type = forms.CharField(
widget=forms.widgets.Select(
choices=user_type_choice,
attrs={'class': "form-control"},
)
)
# 数据库动态的
# 如果从数据库查找,则Forml里面定义的静态字段只会执行一次,所以需要下面动态的
# def __init__(self, *args, **kwargs):
# super(Forml, self).__init__(*args, **kwargs)
# self.fields['book_type'] = forms.CharField(
# widget=forms.widgets.Select(
# choices=models.BookType.objects.values_list('id', 'caption'),
# attrs={'class': "form-control"},
# )
# )
forms
#!/usr/bin/env python
# coding=utf-8
from django.shortcuts import render
from django.http import HttpResponse
from form1.forms import Forml
def form1(req):
f = Forml()
if req.method == 'POST':
f = Forml(req.POST)
if f.is_valid():
print(f.cleaned_data)
else:
# print(f.errors.get('user',None))
# print(f.errors['pwd'][0])
# print(type(f.errors),f.errors)
# from django.forms.utils import ErrorDict
print(type(f.errors), f.errors)
return render(req, 'account/form1.html', {'error': f.errors, 'form': f})
return render(req, 'account/form1.html', {'form': f})
Views
Title
前端index
除此之外还支持自定义字段,具体用法看下面的使用
import re
from django import forms
from django.core.exceptions import ValidationError
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
class PublishForm(forms.Form):
# 这里手机号使用了自己自定义的验证规则
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
cookie和session
一、cookie
1 request.COOKIES['key']
2 request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
3 参数:
4 default: 默认值
5 salt: 加密盐
6 max_age: 后台控制过期时间
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
二、session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
b. 使用
def index(request):
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 用户session的随机字符串
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
# 删除当前用户的所有Session数据
request.session.delete("session_key")
...
数据库session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
b. 使用
同上
缓存session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
b. 使用
同上
文件session
数据库用于做持久化,缓存用于提高效率
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
b. 使用
同上
缓存+数据库session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
b. 使用
同上
备注:保存在客户端
加密session
三、session用户验证
def login_auth(func):
def wrapper(req, *args, **kwargs):
if not req.session.get('is_login', None):
return redirect('/admin/login')
return func(req, *args, **kwargs)
return wrapper
跨站请求伪造
一、简介
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
二、普通表单
veiw中设置返回值:
return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))
或者
return render(request, 'xxx.html', data) #这里也可以看出render 和 render_to_respone 的区别
html中设置Token:
{% csrf_token %}
三、ajax发送
{% csrf_token %}
前端html
from django.template.context import RequestContext
# Create your views here.
def test(request):
if request.method == 'POST':
print request.POST
return HttpResponse('ok')
return render_to_response('app01/test.html',context_instance=RequestContext(request))
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
Views
django上传文件
一、普通上传文件
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')
Title
二、form上传文件
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)
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
django序列化
一、serializers
# 缺点外键字段不能很好显示
from django.core import serializers
ret = models.BookType.objects.all()
data = serializers.serialize("json", ret)
二、json
有些数据结构不支持,這里可以通过自定义处理器来做扩展
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') elif isinstance(field, Decimal): return str(field) else: return json.JSONEncoder.default(self, field) ret_str = json.dumps(ret, cls=JsonCustomEncoder)
django自定义分页
和tornado一样,只需修改一个地方
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.utils.safestring import mark_safe
class Pagination:
def __init__(self, current_page, all_item):
try:
page = int(current_page)
except:
page = 1
if page < 1:
page = 1
all_pager, c = divmod(all_item, 5)
if c > 0:
all_pager += 1
self.current_page = page
self.all_pager = all_pager
@property
def start(self):
return (self.current_page - 1) * 5
@property
def end(self):
return self.current_page * 5
def string_pager(self, base_url="/admin/manage/"):
list_page = []
if self.all_pager < 11:
s = 1
t = self.all_pager + 1
else: # 总页数大于11
if self.current_page < 6:
s = 1
t = 12
else:
if (self.current_page + 5) < self.all_pager:
s = self.current_page - 5
t = self.current_page + 5 + 1
else:
s = self.all_pager - 11
t = self.all_pager + 1
# 首页
# first = '首页' % base_url
# list_page.append(first)
# 上一页
# 当前页 page
if self.current_page == 1:
prev = '上一页'
else:
prev = '上一页' % (base_url, self.current_page - 1,)
list_page.append(prev)
for p in range(s, t): # 1-11
if p == self.current_page:
temp = '%s' % (base_url, p, p)
else:
temp = '%s' % (base_url, p, p)
list_page.append(temp)
if self.current_page == self.all_pager:
nex = '下一页'
else:
nex = '下一页' % (base_url, self.current_page + 1,)
list_page.append(nex)
# 尾页
# last = '尾页' % (base_url, self.all_pager,)
# list_page.append(last)
# 跳转
# jump = """GO""" % ('/index/', )
# script = """"""
# list_page.append(jump)
# list_page.append(script)
str_page = "".join(list_page)
return mark_safe(str_page)
模板
一、基础语法
{{ 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 }}
基本使用
二、自定义
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)
创建任意 .py 文件,如:xx.py
在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
使用simple_tag
{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}
三、使用filter
@register.filter
def detail(value, arg):
# 只能接受两个参数
allcount, remainder = arg.split(',')
allcount = int(allcount)
remainder = int(remainder)
if value % allcount == remainder:
return True
return False
{% for item in detail_list %}
{% if forloop.counter|detail1:"4,0" %}
{{ item.student__name }}
{% endif %}
{% endfor %}
django中间件
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,穿过中间件的顺序就是下面列表的注册顺序
MIDDLEWARE = [
'middleware_test_1.middleware1.testMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
下面看一下流程图
正常流程,request->view-> url->views ->response
如果request里面直接返回了, 或者出现其他问题,直接到最里面的response,不走django里面的视图处理了
自己自定义的中间件类可以定义下面几种方法
- 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)
自己定义的类在最新的django里面需要继承MiddlewareMixin
自定义中间件
from django.utils.deprecation import MiddlewareMixin
class testMiddleware(MiddlewareMixin):
def process_request(self, request):
print(11)
def process_response(self, request, response):
print(22)
return response
创建中间件
MIDDLEWARE = [
'middleware_test_1.middleware1.testMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
注册中间件
django缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
一、配置
# 此为开始调试用,实际内部不做任何操作
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
'KEY_PREFIX': '', # 缓存key的前缀(默认空)
'VERSION': 1, # 缓存key的版本(默认1)
'KEY_FUNCTION' : default_key_func # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
}
}
# 自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys.
Constructs the key used by all other methods. By default it prepends
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
return '%s:%s:%s' % (key_prefix, version, key)
def get_key_func(key_func):
"""
Function to decide which key function to use.
Defaults to ``default_key_func``.
"""
if key_func is not None:
if callable(key_func):
return key_func
else:
return import_string(key_func)
return default_key_func
# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
# 注:其他配置同开发调试版本
内存
# 此缓存将内容保存至文件
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'filetopath',
}
}
# 注:其他配置同开发调试版本
文件
# 此缓存将内容保存至数据库
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表
}
}
# 注:执行创建表命令 python manage.py createcachetable
数据库
# 此缓存使用python-memcached模块连接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
Memcache缓存(python-memcached模块)
# 此缓存使用pylibmc模块连接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
Memcache缓存(pylibmc模块)
二、应用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
全站使用
方式一:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
方式二:
from django.views.decorators.cache import cache_page
urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]
单独视图缓存
a. 引入TemplateTag
{% load cache %}
b. 使用缓存
{% cache 5000 缓存key %}
缓存内容
{% endcache %}
局部视图使用
django信号量
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 # 创建数据库连接时,自动触发
二、使用内置信号
from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created
def callback(sender, **kwargs):
print("xxoo_callback")
print(sender,kwargs)
xxoo.connect(callback)
# xxoo指上述导入的内容
三、自定义信号
a. 定义信号 import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) b. 注册信号 def callback(sender, **kwargs): print("callback") print(sender,kwargs) pizza_done.connect(callback) c. 触发信号 from 路径 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)