Web框架之Django:
(1)简介:
Django是一个由Python写成开源的重量级Web应用框架,采用MTV的框架模式。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。Django的优势在于:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
(2)Django的处理流程:
当用户发出HTTP请求,URLhandler接收用户请求,根据开发人员设置的路由规则匹配相应的处理类
根据请求的类型判断调用的HTTP方法
如果需要连接数据库,Views中的函数将会调用Models的方法,否则直接去Template中取出HTML页面直接返回
调用Models的时候,Models会去数据库读取数据再返回给Views
经过渲染页面一起将最终的HTML页面返回给页面
MTV与MVC:
MTV和MVC的思想是一样的的,只是思想的体现有所不同。
MVC:M管理应用程序的状态,并约束改变状态的行为,一般叫做业务规则;V负责把数据格式化后呈现给用户查看;C接收用户操作,根据访问模型获取数据,并调用视图显示这些数据,控制器(处理器)用于将模型与视图隔离并成为二者之间的联系纽带。
MTV:M代表数据存取层,也就是Model,改成处理与数据相关的所有事务如何存取,如何验证数据的有效性,包含哪些行为与数据相关;T指的是表现层,该层处理与现实相关的行为,如何在页面文档中显示数据,展现内容,也就是Template;V代表业务逻辑层,该层包含存取模型及调取恰当模板的相关逻辑。
Django版的MTV:
Django也是一个MVC框架。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式。
Django设计MVC优美哲学:
1.对象关系映射 (ORM,object-relational mapping):
以Python类形式定义你的数据模型,ORM将模型与关系数据库连接起来,你将得到一个非常容易使用的数据库API,同时你也可以在Django中使用原始的SQL语句。
2.URL 分派:
使用正则表达式匹配URL,你可以设计任意的URL,没有框架的特定限定。像你喜欢的一样灵活。
3.模版系统:
使用Django强大而可扩展的模板语言,可以分隔设计、内容和Python代码。并且具有可继承性。
4.表单处理:
你可以方便的生成各种表单模型,实现表单的有效性检验。可以方便的从你定义的模型实例生成相应的表单。
5.Cache系统:
可以挂在内存缓冲或其它的框架实现超级缓冲一一实现你所需要的粒度。
6.会话(session):
用户登录与权限检查,快速开发用户会话功能。
7.国际化:
内置国际化系统,方便开发出多种语言的网站。
8.自动化的管理界面:
不需要你花大量的工作来创建人员管理和更新内容。Django自带一个ADMIN site,类似于内容管理系统
(3)Django的常用命令:
django-admin startproject sitename # 在当前目录下创建一个Django程序
python manage.py runserver ip:port # 启动服务器,默认是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 # 查看命令列表
(4)Django数据库相关:
默认使用SQLite3数据库的配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
MySQL的配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'', # 数据库应该以utf-8编码以支持中文
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
由于Python开发常用Python3.x,Django连接数据库的时候使用的是MySQL的MySQLdb模块,然而在Python3中还没有此模块,因此需要使用pymysql进行代替,下面的配置代码写入到项目目录的init.py中即可:
import pymysql
pymysql.install_as_MySQLdb()
PostgreSQL数据库的配置:
DATABASES = {
'default': {
'NAME': '',
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'USER': '',
'PASSWORD': ''
}
Oracle数据库的配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': '',
'USER': 'r',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
Django框架对于开发者而言高度透明化,对于不同数据库的具体使用方法是一致的,改变数据库类型只需要变动上述配置即可。
Django中的Model数据库操作:
Django提供了一个抽象层(“Model”)来构建和管理Web应用程序的数据。Django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。关系对象映射(Object Relational Mapping,简称ORM)。
创建Django项目后的目录结构:
.
├── app0 # app应用目录
│ ├── admin.py
│ ├── apps.py
│ ├── init.py
│ ├── migrations
│ │ └── init.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── DjangoAllNotes # 与项目同名的项目目录
│ ├── init.py
│ ├── pycache
│ │ ├── init.cpython-36.pyc
│ │ └── settings.cpython-36.pyc
│ ├── settings.py # 公用的Django配置文件
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── template
创建基本表结构:
在Django中,每一张数据表就是一个类,这些类存在于每个app目录的models.py文件中,执行 python manage.py makemigrations 会根据models.py生成配置文件,再执行 python manage.py migrate 将会连接数据库并创建表结构。
file:models.py
from django.db import models
Create your models here.
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField()
email = models.EmailField()
other = models.TextField()
执行命令:
D:\Codes\Python\DjangoAllNotes>python manage.py makemigrations
Migrations for 'app0':
app0\migrations\0001_initial.py
- Create model UserInfo
D:\Codes\Python\DjangoAllNotes>python manage.py migrate
Operations to perform:
Apply all migrations: admin, app0, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying app0.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying sessions.0001_initial... OK
D:\Codes\Python\DjangoAllNotes>
可视化如下:
其他的字段参数:
1.null = True # 数据库字段是否可以为空
2.blank = True # django的 Admin 中添加数据时是否可允许空值
3.primary_key = False # 主键,对AutoField设置主键后,就会代替原来的自增 id 列
4.auto_now # 自动创建,无论添加或修改,都是当前操作的时间
5.auto_now_add # 自动创建永远是创建时的时间
6.选择:
GENDER_CHOICE = (
(u'男',u'Male'),
(u'女',u'Female'),
)
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
7.max_length # 长度,是CharField必须属性
8.default # 默认值
9.verbose_name # Admin中字段的显示名称
10.name|db_column # 数据库中的字段名称
11.unique = True # 不允许重复
12.db_index = True # 数据库索引
13.editable = True # 在Admin中是否可以编辑
14.error_messages = None # 错误提示
15.auto_created = False # 自动创建
16.help_text # 在Admin中提示帮助信息
17.validators = []
18.upload-to
其他的字段:
1.models.AutoField
自增列,int类型,如果没有设置,默认会生成一个名称为id的列,如果要显示一个自定义的自增列,必须将其设置为主键
2.models.CharField
字符串字段,必须设置max_length属性
3.models.BooleanField
布尔类型,在数据库中的类型使用tinyint类型构造实现,不能为空
4.models.ComaSeparatedIntegerField
用逗号分割的数字,在数据库中是varchar类型,继承自CharField,所以必须 max_lenght 属性
5.models.DateField
日期类型,在数据库中对应date类型,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6.models.DateTimeField
日期类型,在数据库中对应datetime,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
7.models.Decimal
十进制小数类型,在数据库中对应decimal类型,必须指定整数位max_digits和小数位decimal_places
8.models.EmailField
字符串类型(正则表达式邮箱),在数据库中对应varchar类型
9.models.FloatField
浮点类型,在数据库中对应double类型
10.models.IntegerField
整型,在数据库中对应int类型
11.models.BigIntegerField
长整形
12.integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
13.models.IPAddressField
字符串类型(ip4正则表达式)
14.models.GenericIPAddressField
字符串类型(ip4和ip6是可选的),参数protocol可以是:both、ipv4、ipv6,验证时,会根据设置报错
15.models.NullBooleanField
允许为空的布尔类型
16.models.PositiveIntegerFiel
正数范围的Integer
17.models.PositiveSmallIntegerField
正数范围的smallInteger
18.models.SlugField
减号、下划线、字母、数字
19.models.SmallIntegerField
数字,数据库中的字段有:tinyint、smallint、int、bigint
20.models.TextField
字符串,在数据库中对应longtext
21.models.TimeField
时间 HH:MM[:ss[.uuuuuu]]
22.models.URLField
字符串,地址正则表达式
23.models.BinaryField
二进制
24.models.ImageField
图片
25.models.FilePathField
文件
元数据:
db_table = ‘TableName’# 数据库中生成的名称,使用app名称+下划线+类名
index_tohether = [(‘pub_date’,’deadline’)] # 联合索引
unique_together = ((‘drive’,’ restaurant’)) # 联合唯一索引
verbose_name admin中显示的名称
触发Model中的验证和错误提示有两种方式:
1.DjangoAdmin中的错误信息会优先根据Admin内部的ModelForm错误信息提示,如果都成功,才会再验证Model的字段并显示指定的错误信息。
更改Admin中的错误提示:
from django.contrib import admin
Register your models here.
file:admin.py
from django.contrib import admin
from app0 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 = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)
2.调用Model对象的clean_fields方法:
file:models.py
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={'invalid': '格式错.'})
file: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方法是一个钩子,可用于定制操作,如:上述的异常处理。
连表操作:
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
1.一对多:
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
to, # 要进行关联的表名
to_field=None, # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
models.CASCADE,删除关联数据,与之关联也删除
models.DO_NOTHING,删除关联数据,引发错误IntegrityError
models.PROTECT,删除关联数据,引发错误ProtectedError
models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
models.SET,删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
一对一:
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
一对一其实就是 一对多 + 唯一索引,当两个类之间有继承关系时,默认会创建一个一对一字段。
多对多:
ManyToManyField(RelatedField)
to, # 要进行关联的表名
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名字段名=1).values('表名字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件
表的增删改查:
1.对数据进行增加数据:
-- coding:utf-8 --
file:views.py
from django.shortcuts import render, HttpResponse
Create your views here.
def home(request):
from app01 import models
models.UserInfo.objects.create(username='haha', password='123', age=20)
return HttpResponse('Home, 创建数据完成.')
1.1也可以直接传入字典创建:
def home(request):
from app01 import models
dic = {
'username':'tom',
'password':'123',
'age':18,
}
models.UserInfo.objects.create(**dic)
return HttpResponse('Home, 创建数据成功.')
2.删除数据:
def home(request):
from app01 import models
models.UserInfo.objects.filter(username='tom').delete()
3.修改数据:
def home(request):
from app01 import models
models.UserInfo.objects.filter(age=20).update(age=22)
models.UserInfo.objects.all().update(age=22) # 修改全部数据
4.查询数据:
def home(request):
from app01 import models
list = models.UserInfo.objects.all() # 获取全部数据
models.UserInfo.objects.filter(username='tom').first() # 获取第一条数据
获取的数据是个列表,querySet类型。
for item ini list: # 遍历列表
print(item.username)
使用双下划线连接操作:
1.获取个数:
models.Tb1.objects.filter(name='seven').count()
2.比较大小:
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的值
3.是否包含:
models.Tb1.objects.filter(id__in=[11, 22, 33])
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # 相当于not in
4.是否为空:
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]) # 相当于SQL中的between and
7.其他的操作:
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) +')
12.日期:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
13.年月日周时分秒:
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
Entry.objects.filter(timestamp__hour=23)
Entry.objects.filter(time__hour=5)
Entry.objects.filter(timestamp__hour__gte=12)
Entry.objects.filter(timestamp__minute=29)
Entry.objects.filter(time__minute=46)
Entry.objects.filter(timestamp__minute__gte=29)
Entry.objects.filter(timestamp__second=31)
Entry.objects.filter(time__second=2)
Entry.objects.filter(timestamp__second__gte=31)
14.extra:
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None),有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet 修改机制,它能在 QuerySet生成的SQL从句中注入新子句。无论何时你都需要非常小心的使用extra(). 每次使用它时,您都应该转义用户可以使用params控制的任何参数,以防止SQL注入***。由于产品差异的原因,这些自定义的查询难以保障在不同的数据库之间兼容(因为你手写 SQL 代码的原因),而且违背了 DRY 原则,所以如非必要,还是尽量避免写 extra。
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和Q:
from django.db.models import F
models.Tb1.objects.update(num=F('num')+1) #F用于拿到原始数据
##方式一:
from django.db.models import Q
con = Q()
q1 = Q()
q2 = Q()
q1.connecter = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))
q2.children.append(('c1', 10))
q2.children.append(('c1', 23))
q2.children.append(('c1', 12))
con.add('q1', 'AND')
con.add('q1', 'AND')
models.Tb.objects.filter(con)
##方式二:
Q(nid__gt=10)
Q(nid=8) | Q(nid__gt=10)
Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
执行原生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()
利用双下划线和 _set 将表之间的操作连接起来:
1.创建表结构:
from django.db import models
Create your models here.
class UserProfile(models.Model):
user_info = models.OneToOneField('UserInfo')
username = models.CharField(max_length=64)
password = models.CharField(max_length=64)
def __unicode__(self):
return self.username
class UserInfo(models.Model):
user_type_choice = (
(0, u'普通用户'),
(1, u'高级用户'),
)
user_type = models.IntegerField(choices=user_type_choice)
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
address = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class UserGroup(models.Model):
caption = models.CharField(max_length=64)
user_info = models.ManyToManyField('UserInfo')
def __unicode__(self):
return self.caption
class Host(models.Model):
hostname = models.CharField(max_length=64)
ip = models.GenericIPAddressField()
user_group = models.ForeignKey('UserGroup')
def __unicode__(self):
return self.hostname
2.一对一操作:
user_info_obj = models.UserInfo.objects.filter(id=1).first()
print user_info_obj.user_type
print user_info_obj.get_user_type_display()
print user_info_obj.userprofile.password
user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
print user_info_obj.keys()
print user_info_obj.values()
3.一对多操作:
dic = {
"hostname": "名字1",
"ip": "192.168.1.1",
"user_group_id": 1, # 加对象则为"user_group"
}
models.Host.objects.create(**dic)
正向查找一对多
host_obj = models.Host.objects.all()
print(type(host_obj),host_obj)
<class 'django.db.models.query.QuerySet'>
<QuerySet [<Host: 名字1>]>
for item in host_obj:
print(item.hostname)
print(item.user_group.caption)
print(item.user_group.user_info.values())
<QuerySet [{'name': 'nick', 'user_type': 1, 'id': 1, 'email': '630571017@qq.com', 'address': '128号'}]>
usergroup_obj = models.Host.objects.filter(user_group__caption='标题1')
print(usergroup_obj)
反向查找一对多
usergroup_obj = models.UserGroup.objects.get(id=1)
print(usergroup_obj.caption)
ret = usergroup_obj.host_set.all() # 所有关于id=1的host
print(ret)
obj = models.UserGroup.objects.filter(host__ip='192.168.1.1').values('host__id', 'host__hostname')
print(obj)
<QuerySet [{'host__id': 1, 'host__hostname': '名字1'}]>
4.多对多操作:
user_info_obj = models.UserInfo.objects.get(name='nick')
user_info_objs = models.UserInfo.objects.all()
group_obj = models.UserGroup.objects.get(caption='CTO')
group_objs = models.UserGroup.objects.all()
添加数据
group_obj.user_info.add(user_info_obj)
group_obj.user_info.add(*user_info_objs)
删除数据
group_obj.user_info.remove(user_info_obj)
group_obj.user_info.remove(*user_info_objs)
添加数据
user_info_obj.usergroup_set.add(group_obj)
user_info_obj.usergroup_set.add(*group_objs)
删除数据
user_info_obj.usergroup_set.remove(group_obj)
user_info_obj.usergroup_set.remove(*group_objs)
获取数据
print group_obj.user_info.all()
print group_obj.user_info.all().filter(id=1)
获取数据
print user_info_obj.usergroup_set.all()
print user_info_obj.usergroup_set.all().filter(caption='CTO')
print user_info_obj.usergroup_set.all().filter(caption='DBA')
添加多对多
userinfo_id_1 = models.UserInfo.objects.filter(id=1)
usergroup_id_1 = models.UserGroup.objects.filter(id=1).first()
usergroup_id_1.user_info.add(*userinfo_id_1)
(5)Django路由系统:
Django的路由系统本质就是URL正则与调用的视图函数之间的映射表,URL的加载是从配置中开始的。
这样Django也就很好的支持了静态路由,基于正则的动态路由,以及二级路由,同样开发人员也可以自行使用基于请求方法的路由。
urlpatterns = [
url(正则表达式, view函数, 参数, 别名),
Some...
]
参数是可选的要传递给视图函数的默认参数(字典形式)
别名也是可选的
例如:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^one',views.one2one),
url(r'^two',views.one2many),
url(r'^three',views.many2many),
]
其他使用正则的例子:
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),
]
说明:
1.要捕获从URL中的值,用括号括起来,会当参数传入 views 视图。
2.没有必要添加一个斜线,因为每个URL都有。例如,它articles不是/articles。
3.在'r'前面的每个正则表达式字符串中是可选的,但建议。它告诉Python字符串是“原始” -没有什么字符串中应该进行转义。
使用正则分组:
urlpatterns = [
url(r’^index\d{2}/$’,views.index),
url(r’^index2/(?P<id>\d{3})/$’,views.index2),
url(r’^index3/(?P<id>\d{3})/(?P<name>\w+)’,views.index3),
]
def index(request):
return HttpResponse(‘OK’)
def index2(request, id):
print(“id=”+str(id))
return HttpResponse(‘OK’)
def index3(request, id, name):
print(“id=”+str(id))
print(“name=”+str(name))
return HttpResponse(‘OK’)
Django的二级路由示例:
extra_patterns = [
url(r'^reports/$', credit_views.report),
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
from django.conf.urls import include, url
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')), # 这里是个文件
url(r'^credit/', include(extra_patterns)),
]
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'}),
]
需要注意的是,当你加上参数时,对应函数views.year_archive必须加上一个参数,参数名也必须命名为 foo,这样就实现了参数名的静态绑定,放置参数顺序出错。
(6)Django的View视图函数:
HTTP中产生的两大对象:
HTTP请求:HttpRequest
HTTP应答:HttpResponse
HttpRequest对象:
当请求一个HTML页面的时候,Django将会创建一个HttpRequest对象包含原数据的请求,然后Django加载适合的视图,通过HTTPRequest作为视图函数的一地个参数。每个视图负责返回一个HttpResponse响应。
HttpRequest对象的属性:
1.path:请求页面的全路径,不包括域名
2.method:请求中使用的HTTP方法的字符串表示。全大写表示。例如
if req.method=="GET":
Some...
elseif req.method=="POST":
Some...
GET:包含所有HTTP GET参数的类字典对象
POST:包含所有HTTP POST参数的类字典对象
服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用if req.POST来判断是否使用了HTTP POST 方法;应该使用if req.method=="POST"。
3.COOKIES:包含所有cookies的标准Python字典对象;keys和values都是字符串。
4.FILES:包含所有上传文件的类字典对象;FILES中的每一个Key都是<input type="file" name="" />标签中 name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:
filename:上传文件名,用字符串表示
content_type:上传文件的Content Type
content:上传文件的原始内容
5.user:是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。可以通过user的is_authenticated()方法来辨别用户是否登陆:
if req.user.is_authenticated();
只有激活Django中的AuthenticationMiddleware时该属性才可用。
6.session:唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中session支持时该属性才可用。
7.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对象属性:
对于HtppResponse对象来说,是由Django自动创建的牡丹石HTTPResponse对象必须开发人员手动创建,每个View请求处理方法必须返回一个HTTPResponse对象。
HTTPResponse对象常用的方法:
1.页面渲染,render,render_to_response,推荐使用render,因为render功能更为强大。
2.页面跳转,redirect
3.页面传参,locals,可以直接将对应视图中的所有变量全部传递给模板。
示例代码:
def HandlerName(request):
Some...
var0, var1 = 1, 2
Some...
return render_to_response(‘Home.html’, locals())
对于render的:
render(request, template_name, context=None, content_type=None, status=None, using=None)
结合给定的模板与一个给定的上下文,返回一个字典HttpResponse在渲染文本对象。
request和template_name是必须参数,request指的是传来的resquest,template_name指的是HTML模板或模板序列的名称,如果给定的是序列,那么序列中的第一个模板将被引用。
context 一组字典的值添加到模板中。默认情况下,这是一个空的字典。
content_type MIME类型用于生成文档。
status 为响应状态代码。默认值为200
using 这个名字一个模板引擎的使用将模板。
(7)Django模板和模板语言:
要使用模板,必然会牵扯到静态文件的配置,比如CSS,Js等,在Django的项目目录中的settings.py中追加:
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
其中static是存放静态文件的目录,这样就能在HTML页面中引用特效或者图片了。对于模板,其实就是读取模板,模板中嵌套着标签,然后渲染数据的时候,从Model中取出数据插入到模板中,最后用户接收到请求的响应。
模板语言:
{{ item }}
{% for item in list %} <a>{{ item }}</a> {% endfor %}
{% 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.some的形式
自定义标签:
因为在模板语言中不能进行逻辑运算,所以在Django中提供两种自定义的标签,一种是simple_tag,另一种是filter。
simple_tag可以传递任意参数,但是不能用作布尔判断,filter最多只能传递2个参数,可以用做布尔判断,同样的,simple_tag和filter的实现是类似的。
示例代码:
!/usr/bin/env python
-- conding:utf-8 --
file:mycustomtags.py
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 = "<input type='text' id='%s' class='%s' />" %(id,arg,)
return mark_safe(result)
在HTML文件中导入之前创建的Python文件,使用load命令:
{% load mycustomtags %}
使用simple_tag:
{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}
需要在项目目录中的settings.py中配置当前的APP:
INSTALLED_APPS = (
'app0', # app的名称
)
(8)Django的中间件:
中间件示意图:
每一次用户的请求都会一层一层穿过中间件,当不符合中间件的业务逻辑的时候就会直接返回,用户请求到达不了最里层的业务逻辑处理函数,这样可以自定义中间件,在不使用Nginx等第三方工具的时候统计每次用户的访问次数。
中间件其实就是一个Python文件,但是其中的类需要继承自from django.utils.deprecation import MiddlewareMixin,在这个文件中可以创建如下5中函数:
请求到来之前执行
def process_request(self, request):
Some...
数据返回之前执行
def process_reponse(self, request, response):
Some...
return response # 必须返回请求的数据
执行view中的方法之前执行
def process_view(self, request, callback, callback_args, callback_kwargs)
程序出错时执行
def process_exception(self, request, exception)
渲染模板数据时执行
def process_template_response(self, request, response)
需要在项目目录中的settings.py文件中设置:
MIDDLEWARE = [
'middle.first.First',
'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',
]
(8)Django文件上传和Form验证:
自定义文件上传:
def uploadFile(request):
if request.method == 'POST':
obj = request.FILES.get('xxx')
print(obj.name) # 文件名称
f = open(obj,name, 'wb')
for c in obj.chunks():
f.write(c)
f.close()
Form上传:
def upload_file(request):
if request.method == "POST":
obj = request.FILES.get('uploadfile')
f = open(obj.name, 'wb')
for chunk in obj.chunks():
f.write(chunk)
f.close()
return render(request, 'OK.html')
示例代码:
HTML
<form method="post" action="/view1/" enctype="multipart/form-data">
<input type="file" name="ExcelFile" id="id_ExcelFile" />
<input type="submit" value="提交" />
</form>
Form
from django import forms
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()
Ajax上传文件:
HTML:
<div>
{{ up.ExcelFile }}
<input type="button" id="submitj" value="提交" />
</div>
<script src="/static/js/jquery-2.1.4.min.js"></script>
<script>
$('#submitj').bind("click",function () {
var file = $('#id_ExcelFile')[0].files[0];
var form = new FormData();
form.append('ExcelFile', file);
$.ajax({
type:'POST',
url: '/view1/',
data: form,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function(arg){
console.log(arg);
}
})
})
</script>
Form:
lass 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:
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())
(9)Django的Auth认证系统:
auth模块是Django提供的标准权限管理系统,可以提供用户的身份认证,用户组管理,并且和admin模块配合使用。
启用auth模块:
Application definition
INSTALLED_APPS = [
'django.contrib.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指定的位置,这个参数在项目目录中的settings.py中进行设置。
from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def userinfo(request):
Some...
settings 配置
LOGIN_URL = '/index/'
views
@login_required
def userinfo(request):
Some...
(11)跨站请求伪造CSRF:
Django为了用户实现放置跨站请求伪造,通过中间件django.middleware.csrf.CsrfViewMiddleware来完成。而对于Django中设置防跨站请求伪造功能分为全局设置和局部设置。
全局使用就是直接使用django.middleware.csrf.CsrfViewMiddleware,在项目目录中的settings.py中进行配置。使用装饰器可以进行局部的设置:
@csrf_exempt取消当前函数的防跨站请求伪造功能
@csrf_protect仅启用当前函数的防跨站请求伪造功能
使用时要进行导入:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
在Django1.10中,为了防止BREACH***,对cookie-form类型的csrf做了一点改进,即在cookie和form中的token值是不相同的。
应用方式也分为两种:
普通表单使用CSRF:
1.HTML文件中设置令牌:{% csrf_token %}
2.在View函数中设置返回值:return render(request, 'xxx.html', data)
Ajax使用CSRF:
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% csrf_token %}
<input type="button" onclick="Do();" value="Do it"/>
<script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
<script src="/static/plugin/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
var csrftoken = $.cookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
function Do(){
$.ajax({
url:"/app01/test/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
});
}
</script>
</body>
</html>
(12)Django中的Cookie和Session:
获取cookie:
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间
设置cookie:
rep = HttpResponse(...) 或 rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
参数:
key,键
alue='',值
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获取(不是绝对,底层抓包可以获取到也可以被覆盖)
使用jQuery操作cookie:
<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });
Session类型:
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
数据库:
配置 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,默认修改之后才保存(默认)
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")
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
缓存:
配置 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,默认修改之后才保存
文件:
配置 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,默认修改之后才保存
缓存+数据库:
数据库用于做持久化,缓存用于提高效率。
配置 settings.py:
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
引擎
加密cookieSession:
配置 settings.py:
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
引擎
(13)Django的缓存:
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。如果出现多个url匹配同一个view函数的情况,缓存机制会根据每一个不同的url做单独的缓存.Django中提供了6种缓存方式:
1.开发调试:
配置:
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' 函数名
生成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
2.内存:
配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
3.文件:
配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表
}
}
4.数据库:
配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表
}
}
执行创建表命令 python manage.py createcachetable
5.Memcache缓存(python-memcached模块):
配置:
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',
]
}
}
6.Memcache缓存(pylibmc模块):
配置:
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',
]
}
}
使用缓存:
1.全站使用缓存:
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
2.单独视图缓存:
2.1方式一:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
2.2方式二:
from django.views.decorators.cache import cache_page
urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]
3.局部视图使用:
引入TemplateTag:{% load cache %}
使用缓存:
{% cache 5000 缓存key %}
缓存内容
{% endcache %}
(14)Django信号:
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
内置信号:
1.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类,对于每一个类,自动触发
2.Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
3.Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
4.Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
5.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("内置信号_callback")
print(sender,kwargs)
注册信号
内置信号.connect(callback)
或:
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")
自定义信号:
1.定义信号:
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
2.注册信号:
def callback(sender, **kwargs):
print("callback")
print(sender,kwargs)
pizza_done.connect(callback)
3.触发信号:
from 路径 import pizza_done
pizza_done.send(sender='seven',toppings=123, size=456)
(16)Django中的Admin:
Django admin是一个Django提供的后台管理页面,这个管理页面提供完善的HTML和CSS,是的在model中创建表结构后,在admin中就可以增删改查,配置Django的Admin需要以下步骤:
1.创建后台管理员
python manage.py createsuperuser
2.配置URL
url(r'^admin/', include(admin.site.urls))
3.注册和配置Django Admin后台管理页面admin.py:
admin中的配置:
from django.contrib import admin
Register your models here.
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
设置数据表名称:
class UserType(models.Model):
name = models.CharField(max_length=50)
class Meta:
verbose_name = '用户类型'
verbose_name_plural = '用户类型'
在model中还要:
class UserType(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self): # python3 is __str__(self)
return self.name
为数据表添加搜索功能:
from django.contrib import admin
from app01 import models
class UserInfoAdmin(admin.ModelAdmin):
list_display = ('username', 'password', 'email')
search_fields = ('username', 'email')
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
添加快速过滤:
from django.contrib import admin
from app01 import models
class UserInfoAdmin(admin.ModelAdmin):
list_display = ('username', 'password', 'email')
search_fields = ('username', 'email')
list_filter = ('username', 'email')
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
(17)Django中的Form:
Django中的Form一般用来输入HTML或者验证用户输入。
Form:
!/usr/bin/env python
-- coding:utf-8 --
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):
user_type_choice = (
(0, u'普通用户'),
(1, u'高级用户'),
)
user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
attrs={'class': "form-control"}))
title = forms.CharField(max_length=20,
min_length=5,
error_messages={'required': u'标题不能为空',
'min_length': u'标题最少为5个字符',
'max_length': u'标题最多为20个字符'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'标题5-20个字符'}))
memo = forms.CharField(required=False,
max_length=256,
widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = forms.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
View:
def publish(request):
ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
if request.method == 'POST':
request_form = PublishForm(request.POST)
if request_form.is_valid():
request_dict = request_form.clean()
print request_dict
ret['status'] = True
else:
error_msg = request_form.errors.as_json()
ret['error'] = json.loads(error_msg)
return HttpResponse(json.dumps(ret))
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去Form中字段的定义:
class AdminModelForm(forms.ModelForm):
class Meta:
model = models.Admin
#fields = '__all__'
fields = ('username', 'email')
widgets = {
'email' : forms.PasswordInput(attrs={'class':"alex"}),
}