Model
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 MySQLdb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作

1 import MySQLdb 2 3 def GetList(sql): 4 db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') 5 cursor = db.cursor() 6 cursor.execute(sql) 7 data = cursor.fetchall() 8 db.close() 9 return data 10 11 def GetSingle(sql): 12 db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') 13 cursor = db.cursor() 14 cursor.execute(sql) 15 data = cursor.fetchone() 16 db.close() 17 return data
View Code
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
一、创建表
1、基本结构
|
1 2 3 4 5 6 |
|

1 AutoField(Field) 2 - int自增列,必须填入参数 primary_key=True 3 4 BigAutoField(AutoField) 5 - bigint自增列,必须填入参数 primary_key=True 6 7 注:当model中如果没有自增列,则自动会创建一个列名为id的列 8 from django.db import models 9 10 class UserInfo(models.Model): 11 # 自动创建一个列名为id的且为自增的整数列 12 username = models.CharField(max_length=32) 13 14 class Group(models.Model): 15 # 自定义自增列 16 nid = models.AutoField(primary_key=True) 17 name = models.CharField(max_length=32) 18 19 SmallIntegerField(IntegerField): 20 - 小整数 -32768 ~ 32767 21 22 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) 23 - 正小整数 0 ~ 32767 24 IntegerField(Field) 25 - 整数列(有符号的) -2147483648 ~ 2147483647 26 27 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) 28 - 正整数 0 ~ 2147483647 29 30 BigIntegerField(IntegerField): 31 - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 32 33 自定义无符号整数字段 34 35 class UnsignedIntegerField(models.IntegerField): 36 def db_type(self, connection): 37 return 'integer UNSIGNED' 38 39 PS: 返回值为字段在数据库中的属性,Django字段默认的值为: 40 'AutoField': 'integer AUTO_INCREMENT', 41 'BigAutoField': 'bigint AUTO_INCREMENT', 42 'BinaryField': 'longblob', 43 'BooleanField': 'bool', 44 'CharField': 'varchar(%(max_length)s)', 45 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 46 'DateField': 'date', 47 'DateTimeField': 'datetime', 48 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 49 'DurationField': 'bigint', 50 'FileField': 'varchar(%(max_length)s)', 51 'FilePathField': 'varchar(%(max_length)s)', 52 'FloatField': 'double precision', 53 'IntegerField': 'integer', 54 'BigIntegerField': 'bigint', 55 'IPAddressField': 'char(15)', 56 'GenericIPAddressField': 'char(39)', 57 'NullBooleanField': 'bool', 58 'OneToOneField': 'integer', 59 'PositiveIntegerField': 'integer UNSIGNED', 60 'PositiveSmallIntegerField': 'smallint UNSIGNED', 61 'SlugField': 'varchar(%(max_length)s)', 62 'SmallIntegerField': 'smallint', 63 'TextField': 'longtext', 64 'TimeField': 'time', 65 'UUIDField': 'char(32)', 66 67 BooleanField(Field) 68 - 布尔值类型 69 70 NullBooleanField(Field): 71 - 可以为空的布尔值 72 73 CharField(Field) 74 - 字符类型 75 - 必须提供max_length参数, max_length表示字符长度 76 77 TextField(Field) 78 - 文本类型 79 80 EmailField(CharField): 81 - 字符串类型,Django Admin以及ModelForm中提供验证机制 82 83 IPAddressField(Field) 84 - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 85 86 GenericIPAddressField(Field) 87 - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 88 - 参数: 89 protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" 90 unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both" 91 92 URLField(CharField) 93 - 字符串类型,Django Admin以及ModelForm中提供验证 URL 94 95 SlugField(CharField) 96 - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) 97 98 CommaSeparatedIntegerField(CharField) 99 - 字符串类型,格式必须为逗号分割的数字 100 101 UUIDField(Field) 102 - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 103 104 FilePathField(Field) 105 - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 106 - 参数: 107 path, 文件夹路径 108 match=None, 正则匹配 109 recursive=False, 递归下面的文件夹 110 allow_files=True, 允许文件 111 allow_folders=False, 允许文件夹 112 113 FileField(Field) 114 - 字符串,路径保存在数据库,文件上传到指定目录 115 - 参数: 116 upload_to = "" 上传文件的保存路径 117 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage 118 119 ImageField(FileField) 120 - 字符串,路径保存在数据库,文件上传到指定目录 121 - 参数: 122 upload_to = "" 上传文件的保存路径 123 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage 124 width_field=None, 上传图片的高度保存的数据库字段名(字符串) 125 height_field=None 上传图片的宽度保存的数据库字段名(字符串) 126 127 DateTimeField(DateField) 128 - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] 129 130 DateField(DateTimeCheckMixin, Field) 131 - 日期格式 YYYY-MM-DD 132 133 TimeField(DateTimeCheckMixin, Field) 134 - 时间格式 HH:MM[:ss[.uuuuuu]] 135 136 DurationField(Field) 137 - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 138 139 FloatField(Field) 140 - 浮点型 141 142 DecimalField(Field) 143 - 10进制小数 144 - 参数: 145 max_digits,小数总长度 146 decimal_places,小数位长度 147 148 BinaryField(Field) 149 - 二进制类型
字段
1 null 数据库中字段是否可以为空
2 db_column 数据库中字段的列名
3 db_tablespace
4 default 数据库中字段的默认值
5 primary_key 数据库中字段是否为主键
6 db_index 数据库中字段是否可以建立索引
7 unique 数据库中字段是否可以建立唯一索引
8 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
9 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
10 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
11
12 verbose_name Admin中显示的字段名称
13 blank Admin中是否允许用户输入为空
14 editable Admin中是否可以编辑
15 help_text Admin中该字段的提示信息
16 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
17 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
18
19 error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
20 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
21 如:{'null': "不能为空.", 'invalid': '格式错误'}
22
23 validators 自定义错误验证(列表类型),从而定制想要的验证规则
24 from django.core.validators import RegexValidator
25 from django.core.validators import EmailValidator,URLValidator,DecimalValidator,/
26 MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
27 如:
28 test = models.CharField(
29 max_length=32,
30 error_messages={
31 'c1': '优先错信息1',
32 'c2': '优先错信息2',
33 'c3': '优先错信息3',
34 },
35 validators=[
36 RegexValidator(regex='root_/d+', message='错误了', code='c1'),
37 RegexValidator(regex='root_112233/d+', message='又错误了', code='c2'),
38 EmailValidator(message='又错误了', code='c3'), ]
39 )
参数
1 class UserInfo(models.Model):
2 nid = models.AutoField(primary_key=True)
3 username = models.CharField(max_length=32)
4 class Meta:
5 # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
6 db_table = "table_name"
7
8 # 联合索引
9 index_together = [
10 ("pub_date", "deadline"),
11 ]
12
13 # 联合唯一索引
14 unique_together = (("driver", "restaurant"),)
15
16 # admin中显示的表名称
17 verbose_name
18
19 # verbose_name加s
20 verbose_name_plural
21
22 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
元信息
1 1.触发Model中的验证和错误提示有两种方式:
2 a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
3 b. 调用Model对象的 clean_fields 方法,如:
4 # models.py
5 class UserInfo(models.Model):
6 nid = models.AutoField(primary_key=True)
7 username = models.CharField(max_length=32)
8
9 email = models.EmailField(error_messages={'invalid': '格式错了.'})
10
11 # views.py
12 def index(request):
13 obj = models.UserInfo(username='11234', email='uu')
14 try:
15 print(obj.clean_fields())
16 except Exception as e:
17 print(e)
18 return HttpResponse('ok')
19
20 # Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
21
22 2.Admin中修改错误提示
23 # admin.py
24 from django.contrib import admin
25 from model_club import models
26 from django import forms
27
28
29 class UserInfoForm(forms.ModelForm):
30 username = forms.CharField(error_messages={'required': '用户名不能为空.'})
31 email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
32 age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})
33
34 class Meta:
35 model = models.UserInfo
36 # fields = ('username',)
37 fields = "__all__"
38
39
40 class UserInfoAdmin(admin.ModelAdmin):
41 form = UserInfoForm
42
43
44 admin.site.register(models.UserInfo, UserInfoAdmin)
拓展知识
2、连表结构
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
应用场景:
- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据

1 ForeignKey(ForeignObject) # ForeignObject(RelatedField)
2 to, # 要进行关联的表名
3 to_field=None, # 要关联的表中的字段名称
4 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
5 - models.CASCADE,删除关联数据,与之关联也删除
6 - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
7 - models.PROTECT,删除关联数据,引发错误ProtectedError
8 - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
9 - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
10 - models.SET,删除关联数据,
11 a. 与之关联的值设置为指定值,设置:models.SET(值)
12 b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
13
14 def func():
15 return 10
16
17 class MyModel(models.Model):
18 user = models.ForeignKey(
19 to="User",
20 to_field="id"
21 on_delete=models.SET(func),)
22 related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
23 related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
24 limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
25 # 如:
26 - limit_choices_to={'nid__gt': 5}
27 - limit_choices_to=lambda : {'nid__gt': 5}
28
29 from django.db.models import Q
30 - limit_choices_to=Q(nid__gt=10)
31 - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
32 - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
33 db_constraint=True # 是否在数据库中创建外键约束
34 parent_link=False # 在Admin中是否显示关联数据
35
36
37 OneToOneField(ForeignKey)
38 to, # 要进行关联的表名
39 to_field=None # 要关联的表中的字段名称
40 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
41
42 ###### 对于一对一 ######
43 # 1. 一对一其实就是 一对多 + 唯一索引
44 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
45 # 如下会在A表中额外增加一个c_ptr_id列且唯一:
46 class C(models.Model):
47 nid = models.AutoField(primary_key=True)
48 part = models.CharField(max_length=12)
49
50 class A(C):
51 id = models.AutoField(primary_key=True)
52 code = models.CharField(max_length=1)
53
54 ManyToManyField(RelatedField)
55 to, # 要进行关联的表名
56 related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
57 related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
58 limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
59 # 如:
60 - limit_choices_to={'nid__gt': 5}
61 - limit_choices_to=lambda : {'nid__gt': 5}
62
63 from django.db.models import Q
64 - limit_choices_to=Q(nid__gt=10)
65 - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
66 - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
67 symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
68 # 做如下操作时,不同的symmetrical会有不同的可选字段
69 models.BB.objects.filter(...)
70
71 # 可选字段有:code, id, m1
72 class BB(models.Model):
73
74 code = models.CharField(max_length=12)
75 m1 = models.ManyToManyField('self',symmetrical=True)
76
77 # 可选字段有: bb, code, id, m1
78 class BB(models.Model):
79
80 code = models.CharField(max_length=12)
81 m1 = models.ManyToManyField('self',symmetrical=False)
82
83 through=None, # 自定义第三张表时,使用字段用于指定关系表
84 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
85 from django.db import models
86
87 class Person(models.Model):
88 name = models.CharField(max_length=50)
89
90 class Group(models.Model):
91 name = models.CharField(max_length=128)
92 members = models.ManyToManyField(
93 Person,
94 through='Membership',
95 through_fields=('group', 'person'),
96 )
97
98 class Membership(models.Model):
99 group = models.ForeignKey(Group, on_delete=models.CASCADE)
100 person = models.ForeignKey(Person, on_delete=models.CASCADE)
101 inviter = models.ForeignKey(
102 Person,
103 on_delete=models.CASCADE,
104 related_name="membership_invites",
105 )
106 invite_reason = models.CharField(max_length=64)
107 db_constraint=True, # 是否在数据库中创建外键约束
108 db_table=None, # 默认创建第三张表时,数据库中表的名称
字段以及参数
二、操作表
1、基本操作

1 # 增 2 # 3 # models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs 4 5 # obj = models.Tb1(c1='xx', c2='oo') 6 # obj.save() 7 8 # 查 9 # 10 # models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议) 11 # models.Tb1.objects.all() # 获取全部 12 # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据 13 14 # 删 15 # 16 # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据 17 18 # 改 19 # models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs 20 # obj = models.Tb1.objects.get(id=1) 21 # obj.c1 = '111' 22 # obj.save() # 修改单条数据
基本操作
2、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来

1 # 获取个数
2 #
3 # models.Tb1.objects.filter(name='seven').count()
4
5 # 大于,小于
6 #
7 # models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
8 # models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
9 # models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
10 # models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
11 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
12
13 # in
14 #
15 # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
16 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
17
18 # isnull
19 # Entry.objects.filter(pub_date__isnull=True)
20
21 # contains
22 #
23 # models.Tb1.objects.filter(name__contains="ven")
24 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
25 # models.Tb1.objects.exclude(name__icontains="ven")
26
27 # range
28 #
29 # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
30
31 # 其他类似
32 #
33 # startswith,istartswith, endswith, iendswith,
34
35 # order by
36 #
37 # models.Tb1.objects.filter(name='seven').order_by('id') # asc
38 # models.Tb1.objects.filter(name='seven').order_by('-id') # desc
39
40 # group by
41 #
42 # from django.db.models import Count, Min, Max, Sum
43 # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
44 # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
45
46 # limit 、offset
47 #
48 # models.Tb1.objects.all()[10:20]
49
50 # regex正则匹配,iregex 不区分大小写
51 #
52 # Entry.objects.get(title__regex=r'^(An?|The) +')
53 # Entry.objects.get(title__iregex=r'^(an?|the) +')
54
55 # date
56 #
57 # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
58 # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
59
60 # year
61 #
62 # Entry.objects.filter(pub_date__year=2005)
63 # Entry.objects.filter(pub_date__year__gte=2005)
64
65 # month
66 #
67 # Entry.objects.filter(pub_date__month=12)
68 # Entry.objects.filter(pub_date__month__gte=6)
69
70 # day
71 #
72 # Entry.objects.filter(pub_date__day=3)
73 # Entry.objects.filter(pub_date__day__gte=3)
74
75 # week_day
76 #
77 # Entry.objects.filter(pub_date__week_day=2)
78 # Entry.objects.filter(pub_date__week_day__gte=2)
79
80 # hour
81 #
82 # Event.objects.filter(timestamp__hour=23)
83 # Event.objects.filter(time__hour=5)
84 # Event.objects.filter(timestamp__hour__gte=12)
85
86 # minute
87 #
88 # Event.objects.filter(timestamp__minute=29)
89 # Event.objects.filter(time__minute=46)
90 # Event.objects.filter(timestamp__minute__gte=29)
91
92 # second
93 #
94 # Event.objects.filter(timestamp__second=31)
95 # Event.objects.filter(time__second=2)
96 # Event.objects.filter(timestamp__second__gte=31)
进阶操作
3、其他操作

1 # extra
2 #
3 # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
4 # Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
5 # Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
6 # Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
7 # Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
8
9 # F
10 #
11 # from django.db.models import F
12 # models.Tb1.objects.update(num=F('num')+1)
13
14
15 # Q
16 #
17 # 方式一:
18 # Q(nid__gt=10)
19 # Q(nid=8) | Q(nid__gt=10)
20 # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
21 # 方式二:
22 # con = Q()
23 # q1 = Q()
24 # q1.connector = 'OR'
25 # q1.children.append(('id', 1))
26 # q1.children.append(('id', 10))
27 # q1.children.append(('id', 9))
28 # q2 = Q()
29 # q2.connector = 'OR'
30 # q2.children.append(('c1', 1))
31 # q2.children.append(('c1', 10))
32 # q2.children.append(('c1', 9))
33 # con.add(q1, 'AND')
34 # con.add(q2, 'AND')
35 #
36 # models.Tb1.objects.filter(con)
37
38
39 # 执行原生SQL
40 #
41 # from django.db import connection, connections
42 # cursor = connection.cursor() # cursor = connections['default'].cursor()
43 # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
44 # row = cursor.fetchone()
其他操作
4、连表操作(了不起的双下划线)
利用双下划线和 _set 将表之间的操作连接起来

1 class UserProfile(models.Model):
2 user_info = models.OneToOneField('UserInfo')
3 username = models.CharField(max_length=64)
4 password = models.CharField(max_length=64)
5
6 def __unicode__(self):
7 return self.username
8
9
10 class UserInfo(models.Model):
11 user_type_choice = (
12 (0, u'普通用户'),
13 (1, u'高级用户'),
14 )
15 user_type = models.IntegerField(choices=user_type_choice)
16 name = models.CharField(max_length=32)
17 email = models.CharField(max_length=32)
18 address = models.CharField(max_length=128)
19
20 def __unicode__(self):
21 return self.name
22
23
24 class UserGroup(models.Model):
25
26 caption = models.CharField(max_length=64)
27
28 user_info = models.ManyToManyField('UserInfo')
29
30 def __unicode__(self):
31 return self.caption
32
33
34 class Host(models.Model):
35 hostname = models.CharField(max_length=64)
36 ip = models.GenericIPAddressField()
37 user_group = models.ForeignKey('UserGroup')
38
39 def __unicode__(self):
40 return self.hostname
表结构实例
1 user_info_obj = models.UserInfo.objects.filter(id=1).first()
2 print user_info_obj.user_type
3 print user_info_obj.get_user_type_display()
4 print user_info_obj.userprofile.password
5
6 user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
7 print user_info_obj.keys()
8 print user_info_obj.values()
一对一操作
类似一对一 1、搜索条件使用 __ 连接 2、获取值时使用 . 连接
一对多
1 user_info_obj = models.UserInfo.objects.get(name=u'武沛齐') 2 user_info_objs = models.UserInfo.objects.all() 3 4 group_obj = models.UserGroup.objects.get(caption='CEO') 5 group_objs = models.UserGroup.objects.all() 6 7 # 添加数据 8 #group_obj.user_info.add(user_info_obj) 9 #group_obj.user_info.add(*user_info_objs) 10 11 # 删除数据 12 #group_obj.user_info.remove(user_info_obj) 13 #group_obj.user_info.remove(*user_info_objs) 14 15 # 添加数据 16 #user_info_obj.usergroup_set.add(group_obj) 17 #user_info_obj.usergroup_set.add(*group_objs) 18 19 # 删除数据 20 #user_info_obj.usergroup_set.remove(group_obj) 21 #user_info_obj.usergroup_set.remove(*group_objs) 22 23 # 获取数据 24 #print group_obj.user_info.all() 25 #print group_obj.user_info.all().filter(id=1) 26 27 # 获取数据 28 #print user_info_obj.usergroup_set.all() 29 #print user_info_obj.usergroup_set.all().filter(caption='CEO') 30 #print user_info_obj.usergroup_set.all().filter(caption='DBA')
多对多操作
扩展:
a、自定义上传

1 def upload_file(request):
2 if request.method == "POST":
3 obj = request.FILES.get('fafafa')
4 f = open(obj.name, 'wb')
5 for chunk in obj.chunks():
6 f.write(chunk)
7 f.close()
8 return render(request, 'file.html')
View Code
b、Form上传文件实例

1 class FileForm(forms.Form): 2 ExcelFile = forms.FileField()
Form
1 from django.db import models 2 3 class UploadFile(models.Model): 4 userid = models.CharField(max_length = 30) 5 file = models.FileField(upload_to = './upload/') 6 date = models.DateTimeField(auto_now_add=True)
Model
1 def UploadFile(request): 2 uf = AssetForm.FileForm(request.POST,request.FILES) 3 if uf.is_valid(): 4 upload = models.UploadFile() 5 upload.userid = 1 6 upload.file = uf.cleaned_data['ExcelFile'] 7 upload.save() 8 9 print upload.file
View
Form
django中的Form一般有两种功能:
- 输入html
- 验证用户输入

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 import re
4 from django import forms
5 from django.core.exceptions import ValidationError
6
7
8 def mobile_validate(value):
9 mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
10 if not mobile_re.match(value):
11 raise ValidationError('手机号码格式错误')
12
13
14 class PublishForm(forms.Form):
15
16 user_type_choice = (
17 (0, u'普通用户'),
18 (1, u'高级用户'),
19 )
20
21 user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
22 attrs={'class': "form-control"}))
23
24 title = forms.CharField(max_length=20,
25 min_length=5,
26 error_messages={'required': u'标题不能为空',
27 'min_length': u'标题最少为5个字符',
28 'max_length': u'标题最多为20个字符'},
29 widget=forms.TextInput(attrs={'class': "form-control",
30 'placeholder': u'标题5-20个字符'}))
31
32 memo = forms.CharField(required=False,
33 max_length=256,
34 widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))
35
36 phone = forms.CharField(validators=[mobile_validate, ],
37 error_messages={'required': u'手机不能为空'},
38 widget=forms.TextInput(attrs={'class': "form-control",
39 'placeholder': u'手机号码'}))
40
41 email = forms.EmailField(required=False,
42 error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
43 widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
Form
1 def publish(request):
2 ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
3 if request.method == 'POST':
4 request_form = PublishForm(request.POST)
5 if request_form.is_valid():
6 request_dict = request_form.clean()
7 print request_dict
8 ret['status'] = True
9 else:
10 error_msg = request_form.errors.as_json()
11 ret['error'] = json.loads(error_msg)
12 return HttpResponse(json.dumps(ret))
View
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义

1 class AdminModelForm(forms.ModelForm):
2
3 class Meta:
4 model = models.Admin
5 #fields = '__all__'
6 fields = ('username', 'email')
7
8 widgets = {
9 'email' : forms.PasswordInput(attrs={'class':"alex"}),
10 }
View Code
跨站请求伪造
一、简介
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
二、应用
1、普通表单
|
1 2 3 4 5 6 7 |
|
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
|
1 2 3 4 5 6 7 8 9 10 |
|
text.html
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
Cookie
1、获取Cookie:
|
1 2 3 4 5 6 |
|
2、设置Cookie:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
|
1 2 |
|
Session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
1、数据库Session
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
2、缓存Session
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
3、文件Session
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
4、缓存+数据库Session
|
1 2 3 4 5 6 7 8 9 |
|
5、加密cookie Session
|
1 2 3 4 5 6 7 |
|
扩展:Session用户验证
|
1 2 3 4 5 6 7 |
|
分页
一、Django内置分页

1 from django.shortcuts import render
2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
3
4 L = []
5 for i in range(999):
6 L.append(i)
7
8 def index(request):
9 current_page = request.GET.get('p')
10
11 paginator = Paginator(L, 10)
12 # per_page: 每页显示条目数量
13 # count: 数据总个数
14 # num_pages:总页数
15 # page_range:总页数的索引范围,如: (1,10),(1,200)
16 # page: page对象
17 try:
18 posts = paginator.page(current_page)
19 # has_next 是否有下一页
20 # next_page_number 下一页页码
21 # has_previous 是否有上一页
22 # previous_page_number 上一页页码
23 # object_list 分页之后的数据列表
24 # number 当前页
25 # paginator paginator对象
26 except PageNotAnInteger:
27 posts = paginator.page(1)
28 except EmptyPage:
29 posts = paginator.page(paginator.num_pages)
30 return render(request, 'index.html', {'posts': posts})
views.py
1 <!DOCTYPE html>
2 <html>
3 <head lang="en">
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8 <ul>
9 {% for item in posts %}
10 <li>{{ item }}</li>
11 {% endfor %}
12 </ul>
13
14 <div class="pagination">
15 <span class="step-links">
16 {% if posts.has_previous %}
17 <a href="?p={{ posts.previous_page_number }}">Previous</a>
18 {% endif %}
19 <span class="current">
20 Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
21 </span>
22 {% if posts.has_next %}
23 <a href="?p={{ posts.next_page_number }}">Next</a>
24 {% endif %}
25 </span>
26
27 </div>
28 </body>
29 </html>
Html
1 from django.shortcuts import render
2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
3
4
5 class CustomPaginator(Paginator):
6 def __init__(self, current_page, max_pager_num, *args, **kwargs):
7 """
8 :param current_page: 当前页
9 :param max_pager_num:最多显示的页码个数
10 :param args:
11 :param kwargs:
12 :return:
13 """
14 self.current_page = int(current_page)
15 self.max_pager_num = max_pager_num
16 super(CustomPaginator, self).__init__(*args, **kwargs)
17
18 def page_num_range(self):
19 # 当前页面
20 # self.current_page
21 # 总页数
22 # self.num_pages
23 # 最多显示的页码个数
24 # self.max_pager_num
25 print(1)
26 if self.num_pages < self.max_pager_num:
27 return range(1, self.num_pages + 1)
28 print(2)
29 part = int(self.max_pager_num / 2)
30 if self.current_page - part < 1:
31 return range(1, self.max_pager_num + 1)
32 print(3)
33 if self.current_page + part > self.num_pages:
34 return range(self.num_pages + 1 - self.max_pager_num, self.num_pages + 1)
35 print(4)
36 return range(self.current_page - part, self.current_page + part + 1)
37
38
39 L = []
40 for i in range(999):
41 L.append(i)
42
43 def index(request):
44 current_page = request.GET.get('p')
45 paginator = CustomPaginator(current_page, 11, L, 10)
46 # per_page: 每页显示条目数量
47 # count: 数据总个数
48 # num_pages:总页数
49 # page_range:总页数的索引范围,如: (1,10),(1,200)
50 # page: page对象
51 try:
52 posts = paginator.page(current_page)
53 # has_next 是否有下一页
54 # next_page_number 下一页页码
55 # has_previous 是否有上一页
56 # previous_page_number 上一页页码
57 # object_list 分页之后的数据列表
58 # number 当前页
59 # paginator paginator对象
60 except PageNotAnInteger:
61 posts = paginator.page(1)
62 except EmptyPage:
63 posts = paginator.page(paginator.num_pages)
64
65 return render(request, 'index.html', {'posts': posts})
扩展内置分页:views.py
1 <!DOCTYPE html>
2 <html>
3 <head lang="en">
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8
9 <ul>
10 {% for item in posts %}
11 <li>{{ item }}</li>
12 {% endfor %}
13 </ul>
14
15 <div class="pagination">
16 <span class="step-links">
17 {% if posts.has_previous %}
18 <a href="?p={{ posts.previous_page_number }}">Previous</a>
19 {% endif %}
20
21 {% for i in posts.paginator.page_num_range %}
22 <a href="?p={{ i }}">{{ i }}</a>
23 {% endfor %}
24
25 {% if posts.has_next %}
26 <a href="?p={{ posts.next_page_number }}">Next</a>
27 {% endif %}
28 </span>
29
30 <span class="current">
31 Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
32 </span>
33
34 </div>
35 </body>
36 </html>
扩展内置分页:Html
二、自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页…)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页…)
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出,总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]

1 #!/usr/bin/env python 2 # _*_coding:utf-8_*_ 3 from django.utils.safestring import mark_safe 4 5 class PageInfo(object): 6 def __init__(self,current,totalItem,peritems=5): 7 self.__current=current 8 self.__peritems=peritems 9 self.__totalItem=totalItem 10 def From(self): 11 return (self.__current-1)*self.__peritems 12 def To(self): 13 return self.__current*self.__peritems 14 def TotalPage(self): #总页数 15 result=divmod(self.__totalItem,self.__peritems) 16 if result[1]==0: 17 return result[0] 18 else: 19 return result[0]+1 20 21 def Custompager(baseurl,currentPage,totalpage): #基础页,当前页,总页数 22 perPager=11 23 #总页数<11 24 #0 -- totalpage 25 #总页数>11 26 #当前页大于5 currentPage-5 -- currentPage+5 27 #currentPage+5是否超过总页数,超过总页数,end就是总页数 28 #当前页小于5 0 -- 11 29 begin=0 30 end=0 31 if totalpage <= 11: 32 begin=0 33 end=totalpage 34 else: 35 if currentPage>5: 36 begin=currentPage-5 37 end=currentPage+5 38 if end > totalpage: 39 end=totalpage 40 else: 41 begin=0 42 end=11 43 pager_list=[] 44 if currentPage<=1: 45 first="<a href=''>首页</a>" 46 else: 47 first="<a href='%s%d'>首页</a>" % (baseurl,1) 48 pager_list.append(first) 49 50 if currentPage<=1: 51 prev="<a href=''>上一页</a>" 52 else: 53 prev="<a href='%s%d'>上一页</a>" % (baseurl,currentPage-1) 54 pager_list.append(prev) 55 56 for i in range(begin+1,end+1): 57 if i == currentPage: 58 temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i) 59 else: 60 temp="<a href='%s%d'>%d</a>" % (baseurl,i,i) 61 pager_list.append(temp) 62 if currentPage>=totalpage: 63 next="<a href='#'>下一页</a>" 64 else: 65 next="<a href='%s%d'>下一页</a>" % (baseurl,currentPage+1) 66 pager_list.append(next) 67 if currentPage>=totalpage: 68 last="<a href=''>末页</a>" 69 else: 70 last="<a href='%s%d'>末页</a>" % (baseurl,totalpage) 71 pager_list.append(last) 72 result=''.join(pager_list) 73 return mark_safe(result) #把字符串转成html语言
分页实例
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试

1 # 此为开始调试用,实际内部不做任何操作
2 # 配置:
3 CACHES = {
4 'default': {
5 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
6 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
7 'OPTIONS':{
8 'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
9 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
10 },
11 'KEY_PREFIX': '', # 缓存key的前缀(默认空)
12 'VERSION': 1, # 缓存key的版本(默认1)
13 'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
14 }
15 }
16
17
18 # 自定义key
19 def default_key_func(key, key_prefix, version):
20 """
21 Default function to generate keys.
22
23 Constructs the key used by all other methods. By default it prepends
24 the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
25 function with custom key making behavior.
26 """
27 return '%s:%s:%s' % (key_prefix, version, key)
28
29 def get_key_func(key_func):
30 """
31 Function to decide which key function to use.
32
33 Defaults to ``default_key_func``.
34 """
35 if key_func is not None:
36 if callable(key_func):
37 return key_func
38 else:
39 return import_string(key_func)
40 return default_key_func
View Code
b、内存

1 # 此缓存将内容保存至内存的变量中
2 # 配置:
3 CACHES = {
4 'default': {
5 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
6 'LOCATION': 'unique-snowflake',
7 }
8 }
9
10 # 注:其他配置同开发调试版本
View Code
c、文件

1 # 此缓存将内容保存至文件
2 # 配置:
3
4 CACHES = {
5 'default': {
6 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
7 'LOCATION': '/var/tmp/django_cache',
8 }
9 }
10 # 注:其他配置同开发调试版本
View Code
d、数据库

1 # 此缓存将内容保存至数据库
2
3 # 配置:
4 CACHES = {
5 'default': {
6 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
7 'LOCATION': 'my_cache_table', # 数据库表
8 }
9 }
10
11 # 注:执行创建表命令 python manage.py createcachetable
View Code
e、Memcache缓存(python-memcached模块)

1 # 此缓存使用python-memcached模块连接memcache
2
3 CACHES = {
4 'default': {
5 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
6 'LOCATION': '127.0.0.1:11211',
7 }
8 }
9
10 CACHES = {
11 'default': {
12 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
13 'LOCATION': 'unix:/tmp/memcached.sock',
14 }
15 }
16
17 CACHES = {
18 'default': {
19 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
20 'LOCATION': [
21 '172.19.26.240:11211',
22 '172.19.26.242:11211',
23 ]
24 }
25 }
View Code
f、Memcache缓存(pylibmc模块)

1 # 此缓存使用pylibmc模块连接memcache
2
3 CACHES = {
4 'default': {
5 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
6 'LOCATION': '127.0.0.1:11211',
7 }
8 }
9
10 CACHES = {
11 'default': {
12 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
13 'LOCATION': '/tmp/memcached.sock',
14 }
15 }
16
17 CACHES = {
18 'default': {
19 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
20 'LOCATION': [
21 '172.19.26.240:11211',
22 '172.19.26.242:11211',
23 ]
24 }
25 }
View Code
g. Redis缓存(依赖:pip3 install django-redis)

1 CACHES = {
2 "default": {
3 "BACKEND": "django_redis.cache.RedisCache",
4 "LOCATION": "redis://127.0.0.1:6379",
5 "OPTIONS": {
6 "CLIENT_CLASS": "django_redis.client.DefaultClient",
7 "CONNECTION_POOL_KWARGS": {"max_connections": 100}
8 # "PASSWORD": "密码",
9 }
10 }
11 }
View Code
1 from django_redis import get_redis_connection
2 conn = get_redis_connection("default")
视图中链接并操作
2、应用
a. 全站使用

1 使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 2 3 MIDDLEWARE = [ 4 'django.middleware.cache.UpdateCacheMiddleware', 5 # 其他中间件... 6 'django.middleware.cache.FetchFromCacheMiddleware', 7 ] 8 9 CACHE_MIDDLEWARE_ALIAS = "" 10 CACHE_MIDDLEWARE_SECONDS = "" 11 CACHE_MIDDLEWARE_KEY_PREFIX = ""
View Code
b. 单独视图缓存

1 方式一:
2 from django.views.decorators.cache import cache_page
3
4 @cache_page(60 * 15)
5 def my_view(request):
6 ...
7
8 方式二:
9 from django.views.decorators.cache import cache_page
10
11 urlpatterns = [
12 url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
13 ]
View Code
c、局部视图使用

1 a. 引入TemplateTag
2
3 {% load cache %}
4
5 b. 使用缓存
6
7 {% cache 5000 缓存key %}
8 缓存内容
9 {% endcache %}
View Code
更多:猛击这里
序列化
关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。
1、serializers
|
1 2 3 4 5 |
|
2、json.dumps
|
1 2 3 4 5 6 7 8 |
|
由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

1 from django.core.signals import request_finished
2 from django.core.signals import request_started
3 from django.core.signals import got_request_exception
4
5 from django.db.models.signals import class_prepared
6 from django.db.models.signals import pre_init, post_init
7 from django.db.models.signals import pre_save, post_save
8 from django.db.models.signals import pre_delete, post_delete
9 from django.db.models.signals import m2m_changed
10 from django.db.models.signals import pre_migrate, post_migrate
11
12 from django.test.signals import setting_changed
13 from django.test.signals import template_rendered
14
15 from django.db.backends.signals import connection_created
16
17
18 def callback(sender, **kwargs):
19 print("xxoo_callback")
20 print(sender,kwargs)
21
22 xxoo.connect(callback)
23 # xxoo指上述导入的内容
View Code
1 from django.core.signals import request_finished
2 from django.dispatch import receiver
3
4 @receiver(request_finished)
5 def my_callback(sender, **kwargs):
6 print("Request finished!")
View Code
2、自定义信号
a. 定义信号
|
1 2 |
|
b. 注册信号
|
1 2 3 4 5 |
|
c. 触发信号
|
1 2 3 |
|
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。
原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/277541.html