本文将带您了解关于DjangoORM操作的新内容,同时我们还将为您解释djangoorm的操作的相关知识,另外,我们还将为您提供关于Django-Model操作和ORM操作、Django-ORM操作、
本文将带您了解关于Django ORM操作的新内容,同时我们还将为您解释django orm的操作的相关知识,另外,我们还将为您提供关于Django - Model操作 和 ORM操作、Django - ORM操作、Django - 表与ORM操作、django -orm操作总结的实用信息。
本文目录一览:Django ORM操作(django orm的操作)
Django中集成了ORM框架,可以直接使用orm对数据库进行增删查改等操作,相对sql语句来说,orm语句更加简洁易懂,方便开发者进行开发
1.增加数据
数据库中的表有一对一关系,一对多关系和多对多关系,对于这几种关系我们有不同的方法去实现增加数据操作。
一对一关系
对于一对一关系比较简单,我们假设有一张表student,里面有student_id(学号)和name(两个属性),代码如下:
# 使用如下方法时,需要先引入数据库
from .models import Student
# 第一种方法
Student.obects.create(student_id='123456',name='lcs')
# 第二种方法
stu = Student(student_id='123456',name='lcs')
stu.save()
一对多关系
我们在student表中添加一个属性counselor,表示他的辅导员是谁,辅导员对于学生是一对多的关系
# 使用如下方法时,需要先引入数据库
from .models import Student
# 第一种方法
Student.obects.create(student_id='123456',name='lcs',counselor_id=2)
# 第二种方法
stu = Student(student_id='123456',counselor_id=2)
stu.save()
多对多关系
比如说我们在表中添加一个字段teacher,他表示这个学生的老师。显然,一个学生对应多个老师,一个老师对应多个学生,所以这个是多对多关系。
我们新建一个Teacher表,表示这个学校所有的老师
# 同样,我们需要先引入这连个表
from .models import Teacher,Student
# 获得学生和老师
stu = Student.objects.get(name='lcs')
teacher_1 = Teacher.objects.get(name='hch')
teacher_2 = Teacher.objects.get(name='hyh')
# 将两个teacher对象添加到这个学生teacher字段中
stu.teacher.add(teacher_1,teacher_2)
2.删减数据
删除操作比较简单,但是要注意级联删除操作的存在,否则会造成不可预估的后果
# 引入数据表
from .models import student
student.objects.filter(student_id='1213131').delete()
3.查找数据
关于查找数据有比较多的方法,如果只看sql语句的话,有大于,小于,大于等于,小于等于,in操作等,下面介绍一下比较基本的操作
# 引入数据库
from .models import student
# 查找所有数据
student.objects.all()
# 按条件筛选数据,没有返回为空
student.objects.filter(name='lcs')
# 返回符合条件的第一条数据
student.objects.filter(name='lcs').first()
# 返回符合条件的最后一条数据
student.objects.filter(name='lcs').last()
# 按条件返回数据,没有符合条件的数据则报错
student.objects.get(name='lcs')
# 对所有的名字去重后返回
student.objects.values('name').distinct()
下面介绍sql语句中in,>,>=,<,<=等操作
# 引入数据库
from .models import student
# 获取个数
student.objects.filter(name='seven').count()
# 大于,小于
student.objects.filter(age__gt=21) # 获取age大于21的值
student.objects.filter(age__gte=21) # 获取age大于等于21的值
student.objects.filter(age__lt=21) # 获取age小于21的值
student.objects.filter(age__lte=21) # 获取age小于21的值
student.objects.filter(age__lt=20,age__gt=18) # 获取age大于18 且 小于21的值
# in操作
student.objects.filter(age__in=[18,19,20]) # 获取id等于18,20的数据
student.objects.exclude(age__in=[18,20]) # not in
# isnull操作
student.filter(teacher__isnull=True)
# contains操作
student.objects.filter(name__contains="ven")
student.objects.filter(name__icontains="ven")
student.objects.exclude(name__icontains="ven") # icontains大小写不敏感
# range操作
student.objects.filter(age__range=[18,21]) # 年龄在18和21之间的学生
# 其他类似操作
# startswith,istartswith,endswith,iendswith,# order by
student.objects.filter(age=21).order_by('student_id') # asc
student.objects.filter(age=21).order_by('-student_id') # desc
# group by
student.objects.filter(age=20).values('name').annotate(name=Count('name'))
# limit 、offset
student.objects.all()[10:20]
4.更新数据
# 引入数据库
from .models import student
# 第一种方法
obj = student.objects.get(student_id='121212')
obj.age = '20'
obj.save()
# 第二种方法
student.objects.filter(student_id='121212').update(age=20)
Django - Model操作 和 ORM操作
一、字段
字段列表


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 BooleanField(Field)
34 - 布尔值类型
35
36 NullBooleanField(Field):
37 - 可以为空的布尔值
38
39 CharField(Field)
40 - 字符类型
41 - 必须提供max_length参数, max_length表示字符长度
42
43 TextField(Field)
44 - 文本类型
45
46 EmailField(CharField):
47 - 字符串类型,Django Admin以及ModelForm中提供验证机制
48
49 IPAddressField(Field)
50 - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
51
52 GenericIPAddressField(Field)
53 - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
54 - 参数:
55 protocol,用于指定Ipv4或Ipv6, ''both'',"ipv4","ipv6"
56 unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
57
58 URLField(CharField)
59 - 字符串类型,Django Admin以及ModelForm中提供验证 URL
60
61 SlugField(CharField)
62 - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
63
64 CommaSeparatedIntegerField(CharField)
65 - 字符串类型,格式必须为逗号分割的数字
66
67 UUIDField(Field)
68 - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
69
70 FilePathField(Field)
71 - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
72 - 参数:
73 path, 文件夹路径
74 match=None, 正则匹配
75 recursive=False, 递归下面的文件夹
76 allow_files=True, 允许文件
77 allow_folders=False, 允许文件夹
78
79 FileField(Field)
80 - 字符串,路径保存在数据库,文件上传到指定目录
81 - 参数:
82 upload_to = "" 上传文件的保存路径
83 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
84
85 ImageField(FileField)
86 - 字符串,路径保存在数据库,文件上传到指定目录
87 - 参数:
88 upload_to = "" 上传文件的保存路径
89 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
90 width_field=None, 上传图片的高度保存的数据库字段名(字符串)
91 height_field=None 上传图片的宽度保存的数据库字段名(字符串)
92
93 DateTimeField(DateField)
94 - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
95
96 DateField(DateTimeCheckMixin, Field)
97 - 日期格式 YYYY-MM-DD
98
99 TimeField(DateTimeCheckMixin, Field)
100 - 时间格式 HH:MM[:ss[.uuuuuu]]
101
102 DurationField(Field)
103 - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
104
105 FloatField(Field)
106 - 浮点型
107
108 DecimalField(Field)
109 - 10进制小数
110 - 参数:
111 max_digits,小数总长度
112 decimal_places,小数位长度
113
114 BinaryField(Field)
115 - 二进制类型
116
117 字段列表
自定义无符号整数字段


1 class UnsignedIntegerField(models.IntegerField):
2 def db_type(self, connection):
3 return ''integer UNSIGNED''
4
5 PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
6 ''AutoField'': ''integer AUTO_INCREMENT'',
7 ''BigAutoField'': ''bigint AUTO_INCREMENT'',
8 ''BinaryField'': ''longblob'',
9 ''BooleanField'': ''bool'',
10 ''CharField'': ''varchar(%(max_length)s)'',
11 ''CommaSeparatedIntegerField'': ''varchar(%(max_length)s)'',
12 ''DateField'': ''date'',
13 ''DateTimeField'': ''datetime'',
14 ''DecimalField'': ''numeric(%(max_digits)s, %(decimal_places)s)'',
15 ''DurationField'': ''bigint'',
16 ''FileField'': ''varchar(%(max_length)s)'',
17 ''FilePathField'': ''varchar(%(max_length)s)'',
18 ''FloatField'': ''double precision'',
19 ''IntegerField'': ''integer'',
20 ''BigIntegerField'': ''bigint'',
21 ''IPAddressField'': ''char(15)'',
22 ''GenericIPAddressField'': ''char(39)'',
23 ''NullBooleanField'': ''bool'',
24 ''OneToOneField'': ''integer'',
25 ''PositiveIntegerField'': ''integer UNSIGNED'',
26 ''PositiveSmallIntegerField'': ''smallint UNSIGNED'',
27 ''SlugField'': ''varchar(%(max_length)s)'',
28 ''SmallIntegerField'': ''smallint'',
29 ''TextField'': ''longtext'',
30 ''TimeField'': ''time'',
31 ''UUIDField'': ''char(32)'',
32
33 自定义无符号整数字段
注意事项


1 1.触发Model中的验证和错误提示有两种方式:
2 a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
3 b. 使用ModelForm
4 c. 调用Model对象的 clean_fields 方法,如:
5 # models.py
6 class UserInfo(models.Model):
7 nid = models.AutoField(primary_key=True)
8 username = models.CharField(max_length=32)
9
10 email = models.EmailField(error_messages={''invalid'': ''格式错了.''})
11
12 # views.py
13 def index(request):
14 obj = models.UserInfo(username=''11234'', email=''uu'')
15 try:
16 print(obj.clean_fields())
17 except Exception as e:
18 print(e)
19 return HttpResponse(''ok'')
20
21 # Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
22
23 2.Admin中修改错误提示
24 # admin.py
25 from django.contrib import admin
26 from model_club import models
27 from django import forms
28
29
30 class UserInfoForm(forms.ModelForm):
31 age = forms.IntegerField(initial=1, error_messages={''required'': ''请输入数值.'', ''invalid'': ''年龄必须为数值.''})
32
33 class Meta:
34 model = models.UserInfo
35 # fields = (''username'',)
36 fields = "__all__"
37 exclude = [''title'']
38 labels = { ''name'':''Writer'', }
39 help_texts = {''name'':''some useful help text.'',}
40 error_messages={ ''name'':{''max_length'':"this writer name is too long"} }
41 widgets={''name'':Textarea(attrs={''cols'':80,''rows'':20})}
42
43 class UserInfoAdmin(admin.ModelAdmin):
44 form = UserInfoForm
45
46 admin.site.register(models.UserInfo, UserInfoAdmin)
47
48 注意事项
二、字段参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, ''何穗''),(1, ''大表姐''),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{''null'': "不能为空.", ''invalid'': ''格式错误''}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
''c1'': ''优先错信息1'',
''c2'': ''优先错信息2'',
''c3'': ''优先错信息3'',
},
validators=[
RegexValidator(regex=''root_\d+'', message=''错误了'', code=''c1''),
RegexValidator(regex=''root_112233\d+'', message=''又错误了'', code=''c2''),
EmailValidator(message=''又错误了'', code=''c3''), ]
)
三、元信息
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
四、多表关系以及参数
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(可执行对象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values(''表名__字段名'')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={''nid__gt'': 5}
- limit_choices_to=lambda : {''nid__gt'': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
db_constraint=True # 是否在数据库中创建外键约束
parent_link=False # 在Admin中是否显示关联数据
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
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中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={''nid__gt'': 5}
- limit_choices_to=lambda : {''nid__gt'': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(''self'',symmetrical=True)
# 可选字段有: bb, code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(''self'',symmetrical=False)
through=None, # 自定义第三张表时,使用字段用于指定关系表
through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through=''Membership'',
through_fields=(''group'', ''person''),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
db_constraint=True, # 是否在数据库中创建外键约束
db_table=None, # 默认创建第三张表时,数据库中表的名称
五、ORM操作
基本操作


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 # models.Tb1.objects.exclude(name=''seven'') # 获取指定条件的数据
14
15 # 删
16 #
17 # models.Tb1.objects.filter(name=''seven'').delete() # 删除指定条件的数据
18
19 # 改
20 # models.Tb1.objects.filter(name=''seven'').update(gender=''0'') # 将指定条件的数据更新,均支持 **kwargs
21 # obj = models.Tb1.objects.get(id=1)
22 # obj.c1 = ''111''
23 # obj.save() # 修改单条数据
24
25 基本操作
进阶操作


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)
97
98 进阶操作
高级操作


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 # 方式二:
23 # con = Q()
24 # q1 = Q()
25 # q1.connector = ''OR''
26 # q1.children.append((''id'', 1))
27 # q1.children.append((''id'', 10))
28 # q1.children.append((''id'', 9))
29 # q2 = Q()
30 # q2.connector = ''OR''
31 # q2.children.append((''c1'', 1))
32 # q2.children.append((''c1'', 10))
33 # q2.children.append((''c1'', 9))
34 # con.add(q1, ''AND'')
35 # con.add(q2, ''AND'')
36 #
37 # models.Tb1.objects.filter(con)
38
39
40 # 执行原生SQL
41 #
42 # from django.db import connection, connections
43 # cursor = connection.cursor() # cursor = connections[''default''].cursor()
44 # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
45 # row = cursor.fetchone()
46
47 高级操作
其他操作


1 ##################################################################
2 # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
3 ##################################################################
4
5 def all(self)
6 # 获取所有的数据对象
7
8 def filter(self, *args, **kwargs)
9 # 条件查询
10 # 条件可以是:参数,字典,Q
11
12 def exclude(self, *args, **kwargs)
13 # 条件查询
14 # 条件可以是:参数,字典,Q
15
16 def select_related(self, *fields)
17 性能相关:表之间进行join连表操作,一次性获取关联的数据。
18 model.tb.objects.all().select_related()
19 model.tb.objects.all().select_related(''外键字段'')
20 model.tb.objects.all().select_related(''外键字段__外键字段'')
21
22 def prefetch_related(self, *lookups)
23 性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
24 # 获取所有用户表
25 # 获取用户类型表where id in (用户表中的查到的所有用户ID)
26 models.UserInfo.objects.prefetch_related(''外键字段'')
27
28
29
30 from django.db.models import Count, Case, When, IntegerField
31 Article.objects.annotate(
32 numviews=Count(Case(
33 When(readership__what_time__lt=treshold, then=1),
34 output_field=CharField(),
35 ))
36 )
37
38 students = Student.objects.all().annotate(num_excused_absences=models.Sum(
39 models.Case(
40 models.When(absence__type=''Excused'', then=1),
41 default=0,
42 output_field=models.IntegerField()
43 )))
44
45 def annotate(self, *args, **kwargs)
46 # 用于实现聚合group by查询
47
48 from django.db.models import Count, Avg, Max, Min, Sum
49
50 v = models.UserInfo.objects.values(''u_id'').annotate(uid=Count(''u_id''))
51 # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
52
53 v = models.UserInfo.objects.values(''u_id'').annotate(uid=Count(''u_id'')).filter(uid__gt=1)
54 # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
55
56 v = models.UserInfo.objects.values(''u_id'').annotate(uid=Count(''u_id'',distinct=True)).filter(uid__gt=1)
57 # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
58
59 def distinct(self, *field_names)
60 # 用于distinct去重
61 models.UserInfo.objects.values(''nid'').distinct()
62 # select distinct nid from userinfo
63
64 注:只有在PostgreSQL中才能使用distinct进行去重
65
66 def order_by(self, *field_names)
67 # 用于排序
68 models.UserInfo.objects.all().order_by(''-id'',''age'')
69
70 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
71 # 构造额外的查询条件或者映射,如:子查询
72
73 Entry.objects.extra(select={''new_id'': "select col from sometable where othercol > %s"}, select_params=(1,))
74 Entry.objects.extra(where=[''headline=%s''], params=[''Lennon''])
75 Entry.objects.extra(where=["foo=''a'' OR bar = ''a''", "baz = ''a''"])
76 Entry.objects.extra(select={''new_id'': "select id from tb where id > %s"}, select_params=(1,), order_by=[''-nid''])
77
78 def reverse(self):
79 # 倒序
80 models.UserInfo.objects.all().order_by(''-nid'').reverse()
81 # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
82
83
84 def defer(self, *fields):
85 models.UserInfo.objects.defer(''username'',''id'')
86 或
87 models.UserInfo.objects.filter(...).defer(''username'',''id'')
88 #映射中排除某列数据
89
90 def only(self, *fields):
91 #仅取某个表中的数据
92 models.UserInfo.objects.only(''username'',''id'')
93 或
94 models.UserInfo.objects.filter(...).only(''username'',''id'')
95
96 def using(self, alias):
97 指定使用的数据库,参数为别名(setting中的设置)
98
99
100 ##################################################
101 # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
102 ##################################################
103
104 def raw(self, raw_query, params=None, translations=None, using=None):
105 # 执行原生SQL
106 models.UserInfo.objects.raw(''select * from userinfo'')
107
108 # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
109 models.UserInfo.objects.raw(''select id as nid from 其他表'')
110
111 # 为原生SQL设置参数
112 models.UserInfo.objects.raw(''select id as nid from userinfo where nid>%s'', params=[12,])
113
114 # 将获取的到列名转换为指定列名
115 name_map = {''first'': ''first_name'', ''last'': ''last_name'', ''bd'': ''birth_date'', ''pk'': ''id''}
116 Person.objects.raw(''SELECT * FROM some_other_table'', translations=name_map)
117
118 # 指定数据库
119 models.UserInfo.objects.raw(''select * from userinfo'', using="default")
120
121 ################### 原生SQL ###################
122 from django.db import connection, connections
123 cursor = connection.cursor() # cursor = connections[''default''].cursor()
124 cursor.execute("""SELECT * from auth_user where id = %s""", [1])
125 row = cursor.fetchone() # fetchall()/fetchmany(..)
126
127
128 def values(self, *fields):
129 # 获取每行数据为字典格式
130
131 def values_list(self, *fields, **kwargs):
132 # 获取每行数据为元祖
133
134 def dates(self, field_name, kind, order=''ASC''):
135 # 根据时间进行某一部分进行去重查找并截取指定内容
136 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
137 # order只能是:"ASC" "DESC"
138 # 并获取转换后的时间
139 - year : 年-01-01
140 - month: 年-月-01
141 - day : 年-月-日
142
143 models.DatePlus.objects.dates(''ctime'',''day'',''DESC'')
144
145 def datetimes(self, field_name, kind, order=''ASC'', tzinfo=None):
146 # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
147 # kind只能是 "year", "month", "day", "hour", "minute", "second"
148 # order只能是:"ASC" "DESC"
149 # tzinfo时区对象
150 models.DDD.objects.datetimes(''ctime'',''hour'',tzinfo=pytz.UTC)
151 models.DDD.objects.datetimes(''ctime'',''hour'',tzinfo=pytz.timezone(''Asia/Shanghai''))
152
153 """
154 pip3 install pytz
155 import pytz
156 pytz.all_timezones
157 pytz.timezone(‘Asia/Shanghai’)
158 """
159
160 def none(self):
161 # 空QuerySet对象
162
163
164 ####################################
165 # METHODS THAT DO DATABASE QUERIES #
166 ####################################
167
168 def aggregate(self, *args, **kwargs):
169 # 聚合函数,获取字典类型聚合结果
170 from django.db.models import Count, Avg, Max, Min, Sum
171 result = models.UserInfo.objects.aggregate(k=Count(''u_id'', distinct=True), n=Count(''nid''))
172 ===> {''k'': 3, ''n'': 4}
173
174 def count(self):
175 # 获取个数
176
177 def get(self, *args, **kwargs):
178 # 获取单个对象
179
180 def create(self, **kwargs):
181 # 创建对象
182
183 def bulk_create(self, objs, batch_size=None):
184 # 批量插入
185 # batch_size表示一次插入的个数
186 objs = [
187 models.DDD(name=''r11''),
188 models.DDD(name=''r22'')
189 ]
190 models.DDD.objects.bulk_create(objs, 10)
191
192 def get_or_create(self, defaults=None, **kwargs):
193 # 如果存在,则获取,否则,创建
194 # defaults 指定创建时,其他字段的值
195 obj, created = models.UserInfo.objects.get_or_create(username=''root1'', defaults={''email'': ''1111111'',''u_id'': 2, ''t_id'': 2})
196
197 def update_or_create(self, defaults=None, **kwargs):
198 # 如果存在,则更新,否则,创建
199 # defaults 指定创建时或更新时的其他字段
200 obj, created = models.UserInfo.objects.update_or_create(username=''root1'', defaults={''email'': ''1111111'',''u_id'': 2, ''t_id'': 1})
201
202 def first(self):
203 # 获取第一个
204
205 def last(self):
206 # 获取最后一个
207
208 def in_bulk(self, id_list=None):
209 # 根据主键ID进行查找
210 id_list = [11,21,31]
211 models.DDD.objects.in_bulk(id_list)
212
213 def delete(self):
214 # 删除
215
216 def update(self, **kwargs):
217 # 更新
218
219 def exists(self):
220 # 是否有结果
221
222 其他操作
六、其他
Django原生SQL获取cursor字典


1 import pymysql
2 from django.db import connection, connections
3
4 connection.connect()
5 conn = connection.connection
6 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
7 cursor.execute("""SELECT * from app01_userinfo""")
8 row = cursor.fetchone()
9 connection.close()
10
11 Django原生SQL获取cursor字典
数字自增、字符串更新


1 # 数字自增
2 from django.db.models import F
3 models.UserInfo.objects.update(num=F(''num'') + 1)
4
5 # 字符串更新
6 from django.db.models.functions import Concat
7 from django.db.models import Value
8
9 models.UserInfo.objects.update(name=Concat(''name'', ''pwd''))
10 models.UserInfo.objects.update(name=Concat(''name'', Value(''666'')))
11
12 数字自增、字符串更新
ORM函数相关


1 # ########### 基础函数 ###########
2
3 # 1. Concat,用于做类型转换
4 # v = models.UserInfo.objects.annotate(c=Cast(''pwd'', FloatField()))
5
6 # 2. Coalesce,从前向后,查询第一个不为空的值
7 # v = models.UserInfo.objects.annotate(c=Coalesce(''name'', ''pwd''))
8 # v = models.UserInfo.objects.annotate(c=Coalesce(Value(''666''),''name'', ''pwd''))
9
10 # 3. Concat,拼接
11 # models.UserInfo.objects.update(name=Concat(''name'', ''pwd''))
12 # models.UserInfo.objects.update(name=Concat(''name'', Value(''666'')))
13 # models.UserInfo.objects.update(name=Concat(''name'', Value(''666''),Value(''999'')))
14
15 # 4.ConcatPair,拼接(仅两个参数)
16 # v = models.UserInfo.objects.annotate(c=ConcatPair(''name'', ''pwd''))
17 # v = models.UserInfo.objects.annotate(c=ConcatPair(''name'', Value(''666'')))
18
19 # 5.Greatest,获取比较大的值;least 获取比较小的值;
20 # v = models.UserInfo.objects.annotate(c=Greatest(''id'', ''pwd'',output_field=FloatField()))
21
22 # 6.Length,获取长度
23 # v = models.UserInfo.objects.annotate(c=Length(''name''))
24
25 # 7. Lower,Upper,变大小写
26 # v = models.UserInfo.objects.annotate(c=Lower(''name''))
27 # v = models.UserInfo.objects.annotate(c=Upper(''name''))
28
29 # 8. Now,获取当前时间
30 # v = models.UserInfo.objects.annotate(c=Now())
31
32 # 9. substr,子序列
33 # v = models.UserInfo.objects.annotate(c=Substr(''name'',1,2))
34
35 # ########### 时间类函数 ###########
36 # 1. 时间截取,不保留其他:Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,ExtractSecond, ExtractWeekDay, ExtractYear,
37 # v = models.UserInfo.objects.annotate(c=functions.ExtractYear(''ctime''))
38 # v = models.UserInfo.objects.annotate(c=functions.ExtractMonth(''ctime''))
39 # v = models.UserInfo.objects.annotate(c=functions.ExtractDay(''ctime''))
40 #
41 # v = models.UserInfo.objects.annotate(c=functions.Extract(''ctime'', ''year''))
42 # v = models.UserInfo.objects.annotate(c=functions.Extract(''ctime'', ''month''))
43 # v = models.UserInfo.objects.annotate(c=functions.Extract(''ctime'', ''year_month''))
44 """
45 MICROSECOND
46 SECOND
47 MINUTE
48 HOUR
49 DAY
50 WEEK
51 MONTH
52 QUARTER
53 YEAR
54 SECOND_MICROSECOND
55 MINUTE_MICROSECOND
56 MINUTE_SECOND
57 HOUR_MICROSECOND
58 HOUR_SECOND
59 HOUR_MINUTE
60 DAY_MICROSECOND
61 DAY_SECOND
62 DAY_MINUTE
63 DAY_HOUR
64 YEAR_MONTH
65 """
66
67 # 2. 时间截图,保留其他:Trunc, TruncDate, TruncDay,TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear
68 # v = models.UserInfo.objects.annotate(c=functions.TruncHour(''ctime''))
69 # v = models.UserInfo.objects.annotate(c=functions.TruncDate(''ctime''))
70 # v = models.UserInfo.objects.annotate(c=functions.Trunc(''ctime'',''year''))
71
72 ORM函数相关
ORM自定义函数


1 from django.db.models.functions.base import Func
2 class CustomeFunc(Func):
3 function = ''DATE_FORMAT''
4 template = ''%(function)s(%(expressions)s,%(format)s)''
5
6 def __init__(self, expression, **extra):
7 expressions = [expression]
8 super(CustomeFunc, self).__init__(*expressions, **extra)
9
10 v = models.UserInfo.objects.annotate(c=CustomeFunc(''ctime'',format="''%%Y-%%m''"))
11
12 ORM自定义函数
Django - ORM操作
[TOC]
Django - ORM操作
一. 必知必会13条
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
<6> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<7> order_by(*field): 对查询结果排序
<8> reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
<9> distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<11> first(): 返回第一条记录
<12> last(): 返回最后一条记录
<13> exists(): 如果QuerySet包含数据,就返回True,否则返回False
返回QuerySet对象的方法有
-
all()
-
filter()
-
exclude()
-
order_by()
-
reverse()
-
distinct()
特殊的QuerySet
-
values() 返回一个可迭代的字典序列
-
values_list() 返回一个可迭代的元祖序列
返回具体对象的
-
get()
-
first()
-
last()
返回布尔值的方法有:
- exists()
返回数字的方法有
- count()
单表查询之神奇的双下划线
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and
类似的还有:startswith,istartswith, endswith, iendswith
date字段还可以:
models.Class.objects.filter(first_day__year=2017)
二. ForeignKey操作
正向查找
对象查找(跨表) 语法:
对象.关联字段.字段
示例:
book_obj = models.Book.objects.first() # 第一本书对象
print(book_obj.publisher) # 得到这本书关联的出版社对象
print(book_obj.publisher.name) # 得到出版社对象的名称
字段查找(跨表) 语法:
关联字段__字段
示例:
print(models.Book.objects.values_list("publisher__name"))
反向操作
对象查找 语法:
obj.表名_set
示例:
publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象
books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书
titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
字段查找 语法:
表名__字段
示例:
titles = models.Publisher.objects.values_list("book__title")
三. ManyToManyField
create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
>>> import datetime
>>> models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())
add()
把指定的model对象添加到关联对象集中。
添加对象
>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)
添加id
>>> models.Book.objects.first().authors.add(*[1, 2])
set()
更新model对象的关联对象。
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])
remove()
从关联对象集中移除执行的model对象
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)
clear()
从关联对象集中移除一切对象。
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.clear()
注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
举个例子:
ForeignKey字段没设置null=True时,
class Book(models.Model):
title = models.CharField(max_length=32)
publisher = models.ForeignKey(to=Publisher)
没有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: ''RelatedManager'' object has no attribute ''clear''
当ForeignKey字段设置null=True时,
class Book(models.Model):
name = models.CharField(max_length=32)
publisher = models.ForeignKey(to=Class, null=True)
此时就有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
注意:
对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。
四. 聚合查询和分组查询
聚合
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
示例:
>>> from django.db.models import Avg, Sum, Max, Min, Count
>>> models.Book.objects.all().aggregate(Avg("price"))
{''price__avg'': 13.233333}
如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
>> models.Book.objects.aggregate(average_price=Avg(''price''))
{''average_price'': 13.233333}
如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{''price__avg'': 13.233333, ''price__max'': Decimal(''19.90''), ''price__min'': Decimal(''9.90'')}
分组
我们在这里先复习一下SQL语句的分组。
假设现在有一张公司职员表:
我们使用原生SQL语句,按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;
ORM查询:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
连表查询的分组:
SQL查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
ORM查询:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
五. F查询和Q查询
F查询
在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
示例1:
查询评论数大于收藏数的书籍
from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F(''keep_num''))
Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
models.Book.objects.filter(commnet_num__lt=F(''keep_num'')*2)
修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)
引申:
如果要修改char字段咋办?
如:把所有书名后面加上(第一版)
>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
Q查询
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
示例1:
查询作者名是小仙女或小魔女的
models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))
你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。
示例:查询作者名字是小仙女并且不是2018年出版的书的书名。
>>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
<QuerySet [(''番茄物语'',)]>
查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
例如:查询出版年份是2017或2018,书名中带物语的所有书。
>>> models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物语")
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>, <Book: 橘子物语>]>
六. 锁和事务
锁
select_for_update(nowait=False, skip_locked=False)
返回一个锁住行直到事务结束的查询集,如果数据库支持,它将生成一个 SELECT ... FOR UPDATE 语句。
举个例子:
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。 如果这不想要使查询阻塞的话,使用select_for_update(nowait=True)。 如果其它事务持有冲突的锁, 那么查询将引发 DatabaseError 异常。你也可以使用select_for_update(skip_locked=True)忽略锁定的行。 nowait和skip_locked是互斥的,同时设置会导致ValueError。
目前,postgresql,oracle和mysql数据库后端支持select_for_update()。 但是,MySQL不支持nowait和skip_locked参数。
使用不支持这些选项的数据库后端(如MySQL)将nowait=True或skip_locked=True转换为select_for_update()将导致抛出DatabaseError异常,这可以防止代码意外终止。
事务
import os
if __name__ == ''__main__'':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
import datetime
from app01 import models
try:
from django.db import transaction
with transaction.atomic():
new_publisher = models.Publisher.objects.create(name="火星出版社")
models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
except Exception as e:
print(str(e))
七. Django ORM执行原生SQL
Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。
执行原生查询
raw()管理器方法用于原始的SQL查询,并返回模型的实例:
注意:raw()语法查询必须包含主键。
这个方法执行原始的SQL查询,并返回一个django.db.models.query.RawQuerySet 实例。 这个RawQuerySet 实例可以像一般的QuerySet那样,通过迭代来提供对象实例。
举个例子:
class Person(models.Model):
first_name = models.CharField(...)
last_name = models.CharField(...)
birth_date = models.DateField(...)
可以像下面这样执行原生SQL语句
>>> for p in Person.objects.raw(''SELECT * FROM myapp_person''):
... print(p)
raw()查询可以查询其他表的数据。
举个例子:
ret = models.Student.objects.raw(''select id, tname as hehe from app02_teacher'')
for i in ret:
print(i.id, i.hehe)
raw()方法自动将查询字段映射到模型字段。还可以通过translations参数指定一个把查询的字段名和ORM对象实例的字段名互相对应的字典
d = {''tname'': ''haha''}
ret = models.Student.objects.raw(''select * from app02_teacher'', translations=d)
for i in ret:
print(i.id, i.sname, i.haha)
原生SQL还可以使用参数,注意不要自己使用字符串格式化拼接SQL语句,防止SQL注入!
d = {''tname'': ''haha''}
ret = models.Student.objects.raw(''select * from app02_teacher where id > %s'', translations=d, params=[1,])
for i in ret:
print(i.id, i.sname, i.haha)
直接执行自定义SQL
有时候raw()方法并不十分好用,很多情况下我们不需要将查询结果映射成模型,或者我们需要执行DELETE、 INSERT以及UPDATE操作。在这些情况下,我们可以直接访问数据库,完全避开模型层。
我们可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库。
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections[''default''].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
ret = cursor.fetchone()
Django - 表与ORM操作
Django - 表与ORM操作
一. 模板语言
模板中也有自己的语言, 该语言可以实现数据展示
- {{ 变量 }}
- 循环
{% for i in all_publisher %}
{{ forloop.counter }} # 当前循环的测试
{% endfor %}
•{{ item }}
•{% for item in item_list %} <a>{{ item }}</a> {% 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 }}


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/css/bootstrap.css">
<link rel="stylesheet" href="/static/css/dsb.css">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">图书管理系统</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard</a></li>
<li><a href="#">Settings</a></li>
<li><a href="#">Profile</a></li>
<li><a href="#">Help</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search...">
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li ><a href="/index/">作家列表 <span class="sr-only">(current)</span></a></li>
<li><a href="/book_list/">书籍列表</a></li>
<li class="active"><a href="/auth_list/">作家列表</a></li>
<li><a href="#">Export</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">作家展示</h3>
</div>
<div class="panel-body">
<a class="btn btn-primary " href="/add_auth/">添加</a>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>序号</th>
<th>ID</th>
<th>姓名</th>
<th>代表作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for i in all_auth %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.pk }}</td>
<td>{{ i.name }}</td>
<td>
{% for book in i.books.all %}
{{ book.title }}
{% endfor %}
</td>
<td>
<a class="btn btn-success btn-sm" href="/edit_auth/?pk={{ i.pk }}">编辑</a>
<a class="btn btn-danger btn-sm" href="/del_auth/?pk={{ i.pk }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
二. 表结构
1. 基本表结构
from django.db import models
class userinfo(models.Model):
name = models.CharField(max_length=30)
email = models.EmailField()
memo = models.TextField()


AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
自定义无符号整数字段
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return ''integer UNSIGNED''
PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
''AutoField'': ''integer AUTO_INCREMENT'',
''BigAutoField'': ''bigint AUTO_INCREMENT'',
''BinaryField'': ''longblob'',
''BooleanField'': ''bool'',
''CharField'': ''varchar(%(max_length)s)'',
''CommaSeparatedIntegerField'': ''varchar(%(max_length)s)'',
''DateField'': ''date'',
''DateTimeField'': ''datetime'',
''DecimalField'': ''numeric(%(max_digits)s, %(decimal_places)s)'',
''DurationField'': ''bigint'',
''FileField'': ''varchar(%(max_length)s)'',
''FilePathField'': ''varchar(%(max_length)s)'',
''FloatField'': ''double precision'',
''IntegerField'': ''integer'',
''BigIntegerField'': ''bigint'',
''IPAddressField'': ''char(15)'',
''GenericIPAddressField'': ''char(39)'',
''NullBooleanField'': ''bool'',
''OneToOneField'': ''integer'',
''PositiveIntegerField'': ''integer UNSIGNED'',
''PositiveSmallIntegerField'': ''smallint UNSIGNED'',
''SlugField'': ''varchar(%(max_length)s)'',
''SmallIntegerField'': ''smallint'',
''TextField'': ''longtext'',
''TimeField'': ''time'',
''UUIDField'': ''char(32)'',
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, ''both'',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)
- 二进制类型


null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, ''何穗''),(1, ''大表姐''),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{''null'': "不能为空.", ''invalid'': ''格式错误''}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
''c1'': ''优先错信息1'',
''c2'': ''优先错信息2'',
''c3'': ''优先错信息3'',
},
validators=[
RegexValidator(regex=''root_\d+'', message=''错误了'', code=''c1''),
RegexValidator(regex=''root_112233\d+'', message=''又错误了'', code=''c2''),
EmailValidator(message=''又错误了'', code=''c3''), ]
)


class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
更多:https://docs.djangoproject.com/en/1.10/ref/models/options/


1.触发Model中的验证和错误提示有两种方式:
a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
b. 调用Model对象的 clean_fields 方法,如:
# models.py
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={''invalid'': ''格式错了.''})
# views.py
def index(request):
obj = models.UserInfo(username=''11234'', email=''uu'')
try:
print(obj.clean_fields())
except Exception as e:
print(e)
return HttpResponse(''ok'')
# Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
2.Admin中修改错误提示
# admin.py
from django.contrib import admin
from model_club import models
from django import forms
class UserInfoForm(forms.ModelForm):
username = forms.CharField(error_messages={''required'': ''用户名不能为空.''})
email = forms.EmailField(error_messages={''invalid'': ''邮箱格式错误.''})
age = forms.IntegerField(initial=1, error_messages={''required'': ''请输入数值.'', ''invalid'': ''年龄必须为数值.''})
class Meta:
model = models.UserInfo
# fields = (''username'',)
fields = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)
2. 连表结构
一对多: models.ForeignKey(其他表)
多对多: models.ManyToManyField(其他表)
一对一:models.OneToOneFileld(其他表)
应用场景:
- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择) 例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框 例如:创建用户信息,需要为用户指定多个爱好
- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了 例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据


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(可执行对象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values(''表名__字段名'')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={''nid__gt'': 5}
- limit_choices_to=lambda : {''nid__gt'': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
db_constraint=True # 是否在数据库中创建外键约束
parent_link=False # 在Admin中是否显示关联数据
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
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中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={''nid__gt'': 5}
- limit_choices_to=lambda : {''nid__gt'': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(''self'',symmetrical=True)
# 可选字段有: bb, code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(''self'',symmetrical=False)
through=None, # 自定义第三张表时,使用字段用于指定关系表
through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through=''Membership'',
through_fields=(''group'', ''person''),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
db_constraint=True, # 是否在数据库中创建外键约束
db_table=None, # 默认创建第三张表时,数据库中表的名称
三. 表操作
1. 基本操作


# 增
#
# models.Tb1.objects.create(c1=''xx'', c2=''oo'') 增加一条数据,可以接受字典类型数据 **kwargs
# obj = models.Tb1(c1=''xx'', c2=''oo'')
# obj.save()
# 查
#
# models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议)
# models.Tb1.objects.all() # 获取全部
# models.Tb1.objects.filter(name=''seven'') # 获取指定条件的数据
# 删
#
# models.Tb1.objects.filter(name=''seven'').delete() # 删除指定条件的数据
# 改
# models.Tb1.objects.filter(name=''seven'').update(gender=''0'') # 将指定条件的数据更新,均支持 **kwargs
# obj = models.Tb1.objects.get(id=1)
# obj.c1 = ''111''
# obj.save() # 修改单条数据
2. 进阶操作(上下滑线滑线)
利用上下滑线将字段和对应的操作连接起来


# 获取个数
#
# models.Tb1.objects.filter(name=''seven'').count()
# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
# in
#
# models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
# isnull
# Entry.objects.filter(pub_date__isnull=True)
# contains
#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
# models.Tb1.objects.exclude(name__icontains="ven")
# range
#
# models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
# 其他类似
#
# startswith,istartswith, endswith, iendswith,
# order by
#
# models.Tb1.objects.filter(name=''seven'').order_by(''id'') # asc
# models.Tb1.objects.filter(name=''seven'').order_by(''-id'') # desc
# group by
#
# from django.db.models import Count, Min, Max, Sum
# models.Tb1.objects.filter(c1=1).values(''id'').annotate(c=Count(''num''))
# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
# limit 、offset
#
# models.Tb1.objects.all()[10:20]
# regex正则匹配,iregex 不区分大小写
#
# Entry.objects.get(title__regex=r''^(An?|The) +'')
# Entry.objects.get(title__iregex=r''^(an?|the) +'')
# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)
# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)
# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)
# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
# hour
#
# Event.objects.filter(timestamp__hour=23)
# Event.objects.filter(time__hour=5)
# Event.objects.filter(timestamp__hour__gte=12)
# minute
#
# Event.objects.filter(timestamp__minute=29)
# Event.objects.filter(time__minute=46)
# Event.objects.filter(timestamp__minute__gte=29)
# second
#
# Event.objects.filter(timestamp__second=31)
# Event.objects.filter(time__second=2)
# Event.objects.filter(timestamp__second__gte=31)
3. 其他操作


# extra
#
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# Entry.objects.extra(select={''new_id'': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=[''headline=%s''], params=[''Lennon''])
# Entry.objects.extra(where=["foo=''a'' OR bar = ''a''", "baz = ''a''"])
# Entry.objects.extra(select={''new_id'': "select id from tb where id > %s"}, select_params=(1,), order_by=[''-nid''])
# F
#
# from django.db.models import F
# models.Tb1.objects.update(num=F(''num'')+1)
# Q
#
# 方式一:
# Q(nid__gt=10)
# Q(nid=8) | Q(nid__gt=10)
# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
# 方式二:
# con = Q()
# q1 = Q()
# q1.connector = ''OR''
# q1.children.append((''id'', 1))
# q1.children.append((''id'', 10))
# q1.children.append((''id'', 9))
# q2 = Q()
# q2.connector = ''OR''
# q2.children.append((''c1'', 1))
# q2.children.append((''c1'', 10))
# q2.children.append((''c1'', 9))
# con.add(q1, ''AND'')
# con.add(q2, ''AND'')
#
# models.Tb1.objects.filter(con)
# 执行原生SQL
#
# from django.db import connection, connections
# cursor = connection.cursor() # cursor = connections[''default''].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()
4. 连表操作
利用下划线和_set将表之间的操作连接起来


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


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()


类似一对一
1、搜索条件使用 __ 连接
2、获取值时使用 . 连接


user_info_obj = models.UserInfo.objects.get(name=u''武沛齐'')
user_info_objs = models.UserInfo.objects.all()
group_obj = models.UserGroup.objects.get(caption=''CEO'')
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=''CEO'')
#print user_info_obj.usergroup_set.all().filter(caption=''DBA'')
扩展:
a.自定义上传


def upload_file(request):
if request.method == "POST":
obj = request.FILES.get(''fafafa'')
f = open(obj.name, ''wb'')
for chunk in obj.chunks():
f.write(chunk)
f.close()
return render(request, ''file.html'')
b.Form上传文件实例


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
四. ORM
1. ORM的对应关系
类 -> 表
对象 -> 记录(数据行)
属性 -> 字段
2. ORM操作
a. 查询
1. models.Publisher(既类名).objects.all() #查询所有的数据 -> 对象列表
2. models.(类名).objects.get(条件) #获取满足条件的一个对象 -> 单独的对象
3. models.(类名).objects.filter() #获取满足条件的所有对象 -> 对象列表
4. models.(类名).objects.all().order_by(''id'') 排序 ->对象列表
5. pub_obj(既主键对象的类名).pk ->主键
6. pub_obj.name
7. 外键
book_obj(既设置了外键被的表的获取的对象).publisher -> 关联的对象
book_obj.publisher_id -> 从book表中获取关联对象的ID
book_obj.publisher.name -> 关联的对象的属性
8. 多对多
author_obj.books -> 管理对象
author_obj.books.all() -> 关联的所有的对象 对象列表
book_obj.author_set -> 管理对象
b.增加
1. models.Publisher.objects.create(name=''xx'') -> 对象
2. 外键
models.Book.objects.create(name=''xxx'', publisher=pub_obj)
models.Book.objexts.create)name=''xxx'', publisher_id=pub_obj.id)
3. 多对多
models.Author.object.create(name=''xxxx'') ->author_obj
author_obj.book.set([多个要关联的对象])
author_obj.book.set([多个要关联的对象的id])
c.删除
1. models.Author.objects.get(id=1).delete()
2. models.Author.objects.filter(id=1).delect()
d.修改
1. pub_obj.name=''new_xxx''
2. pub_obj.save()
3. 外键
book_obj.title = ''xxx''
book_obj.publisher = pub_obj 或者book_obj.publisher_id=pub_obj.id
book_obj.save()
4. 多对多
author_obj.name=''new_name''
author_obj.save()
author_obj.book.set([多个要关联对象]) 或 author_obj.book.set([多个要关联对象的id])


from django.shortcuts import render,redirect,HttpResponse
from cou_sele import models
# Create your views here.
def classes(request):
all_class = models.Classes.objects.all().order_by(''cid'')
return render(request, ''class_list.html'', {''all_class'':all_class})
def add_classes(request):
err_msg, obj = '''', ''''
if request.method == ''POST'':
new_name = request.POST.get(''classes_name'')
if not new_name:
err_msg = ''兄弟,空的啊''
obj = models.Classes.objects.filter(name=''new_name'')
if obj:
err_msg = ''兄弟,重复了''
if new_name and not obj:
models.Classes.objects.create(name=new_name)
return redirect(''/class_list'')
return render(request, ''add_classes.html'', {''err_msg'':err_msg})
def del_classes(request):
pk = request.GET.get(''pk'')
if not models.Classes.objects.filter(pk=pk):
return HttpResponse(''数据不存在'')
models.Classes.objects.get(pk=pk).delete()
return redirect(''/class_list/'')
def edit_classes(request):
err_msg = ''''
pk = request.GET.get(''pk'')
obj_list = models.Classes.objects.filter(pk=pk)
if not obj_list:
return HttpResponse("数据不存在")
obj = obj_list[0]
if request.method == ''POST'':
new_name = request.POST.get(''classes_name'')
if not new_name:
err_msg = ''不能为空''
exist = models.Classes.objects.filter(name=new_name)
if exist:
err_msg = ''已存在''
if new_name and not exist:
# 修改出版社的名称
obj.name = new_name
obj.save() # 向数据库提交
return redirect(''/class_list/'')
return render(request, ''edit_classes.html'', {''obj'': obj, ''err_msg'': err_msg})
def studet_list(request):
all_student = models.Student.objects.all()
return render(request, ''studet_list.html'', {''all_student'': all_student})
def add_student(request):
err_msg, obj = '''', ''''
if request.method == ''POST'':
new_name = request.POST.get(''student_name'')
if not new_name:
err_msg = ''兄弟,空的啊''
obj = models.Classes.objects.filter(name=''new_name'')
if obj:
err_msg = ''兄弟,重复了''
if new_name and not obj:
models.Classes.objects.create(name=new_name)
return redirect(''/class_list'')
all_class = models.Classes.objects.all()
return render(request, ''add_student.html'', {''all_class'': all_class, ''err_msg'': err_msg})
def del_student(request):
pk = request.GET.get(''pk'')
if not models.Classes.objects.filter(pk=pk):
return HttpResponse(''数据不存在'')
models.Classes.objects.get(pk=pk).delete()
return redirect(''/student_list/'')
def edit_student(request):
err_msg = ''''
pk = request.GET.get(''pk'')
student_obj = models.Student.objects.get(pk=pk)
if not student_obj:
return HttpResponse(''数据不存在'')
if request.method == ''POST'':
new_name = request.POST.get(''new_name'')
classes_id = request.POST.get(''classes_id'')
if not new_name:
err_msg = ''不能为空''
exist = models.Student.objects.filter(name=new_name)
if exist:
err_msg = ''你瞎啊, 已经有了''
if new_name and not exist:
student_obj.name = new_name
student_obj.classes_id = classes_id
student_obj.save()
return redirect(''/studet_list/'')
all_classes = models.Classes.objects.all()
return render(request, ''edit_student.html'', {''err_msg'': err_msg, ''student_obj'': student_obj, ''all_classes'':all_classes})
def teacher_list(request):
all_teacher = models.Teacher.objects.all()
all_student = models.Student.objects.all()
return render(request, ''teacher_list.html'', {''all_teacher'': all_teacher,''all_student'':all_student})
def add_teacher(request):
err_msg = ''''
if request.method == ''POST'':
new_name = request.POST.get(''new_name'')
student_ids = request.POST.getlist(''stu'')
if not new_name:
err_msg = ''瞎啊,空的''
obj_new_name = models.Teacher.objects.filter(name=new_name)
if obj_new_name:
err_msg = ''瞎啊,重复了''
if new_name and not obj_new_name:
author_obj = models.Teacher.objects.create(name=new_name)
author_obj.Student.set(student_ids)
return redirect(''/teacher_list/'')
all_student = models.Student.objects.all()
return render(request, ''add_teacher.html'', {''all_student'': all_student, ''err_msg'': err_msg})
def del_teacher(request):
del_id = request.GET.get(''pk'')
models.Teacher.objects.get(pk = del_id).delete()
return redirect(''/teacher_list/'')
def edit_teacher(request):
err_msg = ''''
pk = request.GET.get(''pk'')
teacher_obj = models.Teacher.objects.get(pk=pk)
if request.method == ''POST'':
name = request.POST.get(''new_name'')
student_ids = request.POST.getlist(''student_id'')
if not name:
err_msg = ''空的''
else:
teacher_obj.name = name
teacher_obj.save()
teacher_obj.Student.set(student_ids)
return redirect(''/teacher_list/'')
all_student = models.Student.objects.all()
return render(request, ''edit_teacher.html'', {''err_msg'':err_msg,''author_obj'': teacher_obj, ''all_student'': all_student})
五. request
1. request.method ->请求方式一共有8种 主要的有 GET/POST
2. request.GET -> url的参数 xxx/?id=1&name=konghui
request.GET.get(''id'')


</thead>
<tbody>
{% for i in all_teacher %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.pk }}</td>
<td>{{ i.name }}</td>
<td>
{% for book in i.Student.all %}
{{ book.name }}
{% endfor %}
</td>
<td>
<a class="btn btn-success btn-sm" href="/edit_teacher/?pk={{ i.pk }}">编辑</a>
<a class="btn btn-danger btn-sm" href="/del_teacher/?pk={{ i.pk }}">删除</a>
</td>
</tr>
{% endfor %}
3.request.POST -> form表单提交的POST的数据{}
六.函数的返回值
1. HttpRequest(''字符串'') -> 返回字符串
2. render(request, ''模板的文件名'', {k1:v1}) -> 返回一个完整的页面
3. request.POST(/''跳转的地址''/) -> 重定向 响应头 location: ''跳转的地址''
django -orm操作总结
前言
Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 MySQLdb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
ORM是什么?:(在django中,根据代码中的类自动生成数据库的表也叫--code first)
ORM:Object Relational Mapping(关系对象映射)
类名对应------》数据库中的表名
类属性对应---------》数据库里的字段
类实例对应---------》数据库表里的一行数据
obj.id obj.name.....类实例对象的属性
Django orm的优势:
Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可;
一、Django连接MySQL
1、创建数据库 (注意设置 数据的字符编码)
由于Django自带的orm是data_first类型的ORM,使用前必须先创建数据库
create database day70 default character set utf8 collate utf8_general_ci;
2、修改project中的settings.py文件中设置 连接 MySQL数据库(Django默认使用的是sqllite数据库)

DATABASES = {
''default'': {
''ENGINE'': ''django.db.backends.mysql'',
''NAME'':''day70'',
''USER'': ''eric'',
''PASSWORD'': ''123123'',
''HOST'': ''192.168.182.128'',
''PORT'': ''3306'',
}
}

扩展:查看orm操作执行的原生SQL语句
在project中的settings.py文件增加

LOGGING = {
''version'': 1,
''disable_existing_loggers'': False,
''handlers'': {
''console'':{
''level'':''DEBUG'',
''class'':''logging.StreamHandler'',
},
},
''loggers'': {
''django.db.backends'': {
''handlers'': [''console''],
''propagate'': True,
''level'':''DEBUG'',
},
}
}

3、修改project 中的__init__py 文件设置 Django默认连接MySQL的方式
import pymysql
pymysql.install_as_MySQLdb()
4、setings文件注册APP

INSTALLED_APPS = [
''django.contrib.admin'',
''django.contrib.auth'',
''django.contrib.contenttypes'',
''django.contrib.sessions'',
''django.contrib.messages'',
''django.contrib.staticfiles'',
''app01.apps.App01Config'',
]

5、models.py创建表
6、进行数据迁移
6.1、在winds cmd或者Linux shell的项目的manage.py目录下执行
python manage.py makemigrations #根据app下的migrations目录中的记录,检测当前model层代码是否发生变化?
python manage.py migrate #把orm代码转换成sql语句去数据库执行
python manage.py migrate --fake #只记录变化,不提交数据库操作
扩展:修改表结构之后常见报错
这个报错:因为表创建之时,新增字段既没有设置默认值,也没有设置新增字段可为空,去对应原有数据导致;
2中解决方法:
1.设置新增字段可以为空
startdate = models.CharField(max_length=255, verbose_name="任务开始时间",null=True, blank=True)
Handledate = models.CharField(max_length=255, verbose_name="开始处理时间",null=True, blank=True)
Handledone = models.CharField(max_length=255, verbose_name="处理完毕时间", null=True, blank=True)
enddate = models.CharField(max_length=255, verbose_name="任务结束时间",null=True, blank=True)
WorkTime_cost=models.CharField(max_length=255,verbose_name=''工作耗时'',null=True, blank=True)
2.设置新增字段默认值为 当前时间
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type ''exit'' to exit this prompt
>>> timezone.now()
3.更多问题
python manage.py makemigrations :把你写在models中的代码翻译成增、删、改的 SQL 语句;
python manage.py migrate;讲python manage.py makemigrations翻译的SQL语句去数据库执行;
python manage.py migrate --fake;假设 migrate 把所有SQL语句执行成功了;
我在使用Django构建表结构的时候很长一段时间都是没有了解以上3条语句的执行意义,所有经常在修改表结构之后出现报错;
出现报错的原因:
无非就是 makemigrations翻译的 SQL,跟数据库里面真实的表结构 相互冲突,增加、删除不了表、外键关系;
所以遇到报错 你应该先把model中的代码注释掉-----》python manage.py migrate --fake------》python manage.py makemigrations
去数据库把已经存在的表、外键删掉(确保数据库目前的状态,可以让makemigrations翻译出来的SQL语句在数据库里执行成功;然后migrate)--------》 python manage.py migrate;
7.设置pycharm可视化MySQL
二、modles.py创建表
ORM字段介绍
Djan提供了很多字段类型,比如URL/Email/IP/ 但是mysql数据没有这些类型,这类型存储到数据库上本质是字符串数据类型,其主要目的是为了封装底层SQL语句;
1、字符串类(以下都是在数据库中本质都是字符串数据类型,此类字段只是在Django自带的admin中生效)
name=models.CharField(max_length=32)

EmailField(CharField):
IPAddressField(Field)
URLField(CharField)
SlugField(CharField)
UUIDField(Field)
FilePathField(Field)
FileField(Field)
ImageField(FileField)
CommaSeparatedIntegerField(CharField)

扩展
models.CharField 对应的是MySQL的varchar数据类型
char 和 varchar的区别 :
char和varchar的共同点是存储数据的长度,不能 超过max_length限制,
不同点是varchar根据数据实际长度存储,char按指定max_length()存储数据;所有前者更节省硬盘空间;
2、时间字段
models.DateTimeField(null=True)
date=models.DateField()
3、数字字段
(max_digits=30,decimal_places=10)总长度30小数位 10位)
数字:
num = models.IntegerField()
num = models.FloatField() 浮点
price=models.DecimalField(max_digits=8,decimal_places=3) 精确浮点
4、枚举字段
choice=(
(1,''男人''),
(2,''女人''),
(3,''其他'')
)
lover=models.IntegerField(choices=choice) #枚举类型
扩展
在数据库存储枚举类型,比外键有什么优势?
1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
2、在modle文件里不能动态增加(选项一成不变用Django的choice)
其他字段

db_index = True 表示设置索引
unique(唯一的意思) = True 设置唯一索引
联合唯一索引
class Meta:
unique_together = (
(''email'',''ctime''),
)
联合索引(不做限制)
index_together = (
(''email'',''ctime''),
)
ManyToManyField(RelatedField) #多对多操作

字段参数介绍
1.数据库级别生效
AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
自定义无符号整数字段
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return ''integer UNSIGNED''
PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
''AutoField'': ''integer AUTO_INCREMENT'',
''BigAutoField'': ''bigint AUTO_INCREMENT'',
''BinaryField'': ''longblob'',
''BooleanField'': ''bool'',
''CharField'': ''varchar(%(max_length)s)'',
''CommaSeparatedIntegerField'': ''varchar(%(max_length)s)'',
''DateField'': ''date'',
''DateTimeField'': ''datetime'',
''DecimalField'': ''numeric(%(max_digits)s, %(decimal_places)s)'',
''DurationField'': ''bigint'',
''FileField'': ''varchar(%(max_length)s)'',
''FilePathField'': ''varchar(%(max_length)s)'',
''FloatField'': ''double precision'',
''IntegerField'': ''integer'',
''BigIntegerField'': ''bigint'',
''IPAddressField'': ''char(15)'',
''GenericIPAddressField'': ''char(39)'',
''NullBooleanField'': ''bool'',
''OneToOneField'': ''integer'',
''PositiveIntegerField'': ''integer UNSIGNED'',
''PositiveSmallIntegerField'': ''smallint UNSIGNED'',
''SlugField'': ''varchar(%(max_length)s)'',
''SmallIntegerField'': ''smallint'',
''TextField'': ''longtext'',
''TimeField'': ''time'',
''UUIDField'': ''char(32)'',
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, ''both'',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)
- 二进制类型
字段
2、Django admin级别生效
针对 dango_admin生效的参数(正则匹配)(使用Django admin就需要关心以下参数!!))
blanke (是否为空)
editable=False 是否允许编辑
help_text="提示信息"提示信息
choices=choice 提供下拉框
error_messages="错误信息" 错误信息
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
''c1'': ''优先错信息1'',
''c2'': ''优先错信息2'',
''c3'': ''优先错信息3'',
},
validators=[
RegexValidator(regex=''root_\d+'', message=''错误了'', code=''c1''),
RegexValidator(regex=''root_112233\d+'', message=''又错误了'', code=''c2''),
EmailValidator(message=''又错误了'', code=''c3''), ]
三、ORM单表操作
0、orm操作前戏
orm使用方式:
orm操作可以使用类实例化,obj.save的方式,也可以使用create()的形式
QuerySet数据类型介绍
QuerySet与惰性机制
所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。
QuerySet特点:
<1> 可迭代的
<2> 可切片
<3>惰性计算和缓存机制
def queryset(request):
books=models.Book.objects.all()[:10] #切片 应用分页
books = models.Book.objects.all()[::2]
book= models.Book.objects.all()[6] #索引
print(book.title)
for obj in books: #可迭代
print(obj.title)
books=models.Book.objects.all() #惰性计算--->等于一个生成器,不应用books不会执行任何SQL操作
# query_set缓存机制1次数据库查询结果query_set都会对应一块缓存,再次使用该query_set时,不会发生新的SQL操作;
#这样减小了频繁操作数据库给数据库带来的压力;
authors=models.Author.objects.all()
for author in authors:
print(author.name)
print(''-------------------------------------'')
models.Author.objects.filter(id=1).update(name=''张某'')
for author in authors:
print(author.name)
#但是有时候取出来的数据量太大会撑爆缓存,可以使用迭代器优雅得解决这个问题;
models.Publish.objects.all().iterator()
return HttpResponse(''OK'')
增加和查询操作
增
def orm(request):
orm2添加一条记录的方法
单表
1、表.objects.create()
models.Publish.objects.create(name=''浙江出版社'',addr="浙江.杭州")
models.Classify.objects.create(category=''武侠'')
models.Author.objects.create(name=''金庸'',sex=''男'',age=89,university=''东吴大学'')
2、类实例化:obj=类(属性=XX) obj.save()
obj=models.Author(name=''吴承恩'',age=518,sex=''男'',university=''龙溪学院'')
obj.save()
1对多
1、表.objects.create()
models.Book.objects.create(title=''笑傲江湖'',price=200,date=1968,classify_id=6, publish_id=6)
2、类实例化:obj=类(属性=X,外键=obj)obj.save()
classify_obj=models.Classify.objects.get(category=''武侠'')
publish_obj=models.Publish.objects.get(name=''河北出版社'')
注意以上获取得是和 book对象 向关联的(外键)的对象
book_obj=models.Book(title=''西游记'',price=234,date=1556,classify=classify_obj,publish=publish_obj)
book_obj.save()
多对多
如果两表之间存在双向1对N关系,就无法使用外键来描述其关系了;
只能使用多对多的方式,新增第三张表关系描述表;
book=models.Book.objects.get(title=''笑傲江湖'')
author1=models.Author.objects.get(name=''金庸'')
author2=models.Author.objects.get(name=''张根'')
book.author.add(author1,author2)
书籍和作者是多对多关系,
切记:如果两表之间存在多对多关系,例如书籍相关的所有作者对象集合,作者也关联的所有书籍对象集合
book=models.Book.objects.get(title=''西游记'')
author=models.Author.objects.get(name=''吴承恩'')
author2 = models.Author.objects.get(name=''张根'')
book.author.add(author,author2)
#add() 添加
#clear() 清空
#remove() 删除某个对象
return HttpResponse(''OK'')
根据条件判断,增加?更新?
# 根据user=user去查找,如果找到更新 如果没有找到创建defaults={} 中的数据
tk = gen_tcoken(username)
models.Token.objects.update_or_create(user=user, defaults={''token'': tk})
删
级联删除
为防止读者跑路,不再赘述!
改
# 修改方式1 update()
models.Book.objects.filter(id=1).update(price=3)
#修改方式2 obj.save()
book_obj=models.Book.objects.get(id=1)
book_obj.price=5
book_obj.save()
查
def ormquery(request):
books=models.Book.objects.all() #------query_set对象集合 [对象1、对象2、.... ]
books=models.Book.objects.filter(id__gt=2,price__lt=100)
book=models.Book.objects.get(title__endswith=''金'') #---------单个对象,没有找到会报错
book1 = models.Book.objects.filter(title__endswith=''金'').first()
book2 = models.Book.objects.filter(title__icontains=''瓶'').last()
books=models.Book.objects.values(''title'',''price'', #-------query_set字典集合 [{一条记录},{一条记录} ]
''publish__name'',
''date'',
''classify__category'', #切记 正向连表:外键字段___对应表字段
''author__name'', #反向连表: 小写表名__对应表字段
''author__sex'', #区别:正向 外键字段__,反向 小写表名__
''author__age'',
''author__university'')
books=models.Book.objects.values(''title'',''publish__name'').distinct()
#exclude 按条件排除。。。
#distinct()去重, exits()查看数据是否存在? 返回 true 和false
a=models.Book.objects.filter(title__icontains=''金'').
return HttpResponse(''OK'')
连表查询
反向连表查询:
1、通过object的形式反向连表, obj.小写表名_set.all()
publish=models.Publish.objects.filter(name__contains=''湖南'').first()
books=publish.book_set.all()
for book in books:
print(book.title)
通过object的形式反向绑定外键关系
authorobj = models.Author.objects.filter(id=1).first()
objects = models.Book.objects.all()
authorobj.book_set.add(*objects)
authorobj.save()
2、通过values双下滑线的形式,objs.values("小写表名__字段")
注意对象集合调用values(),正向查询是外键字段__XX,而反向是小写表名__YY看起来比较容易混淆;
books=models.Publish.objects.filter(name__contains=''湖南'').values(''name'',''book__title'')
authors=models.Book.objects.filter(title__icontains=''我的'').values(''author__name'')
print(authors)
fifter()也支持__小写表名语法进行连表查询:在publish标查询 出版过《笑傲江湖》的出版社
publishs=models.Publish.objects.filter(book__title=''笑傲江湖'').values(''name'')
print(publishs)
查询谁(哪位作者)出版过的书价格大于200元
authors=models.Author.objects.filter(book__price__gt=200).values(''name'')
print(authors)
通过外键字段正向连表查询,出版自保定的书籍;
city=models.Book.objects.filter(publish__addr__icontains=''保定'').values(''title'')
print(city)
1、基本操作
# 增
#
# models.Tb1.objects.create(c1=''xx'', c2=''oo'') 增加一条数据,可以接受字典类型数据 **kwargs
# obj = models.Tb1(c1=''xx'', c2=''oo'')
# obj.save()
# 查
#
# models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议)
# models.Tb1.objects.all() # 获取全部
# models.Tb1.objects.filter(name=''seven'') # 获取指定条件的数据
# 删
#
# models.Tb1.objects.filter(name=''seven'').delete() # 删除指定条件的数据
# 改
# models.Tb1.objects.filter(name=''seven'').update(gender=''0'') # 将指定条件的数据更新,均支持 **kwargs
# obj = models.Tb1.objects.get(id=1)
# obj.c1 = ''111''
# obj.save() # 修改单条数据
基本操作
2、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来
# 获取个数
#
# models.Tb1.objects.filter(name=''seven'').count()
# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
# in
#
# models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
# isnull
# Entry.objects.filter(pub_date__isnull=True)
# contains
#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
# models.Tb1.objects.exclude(name__icontains="ven")
# range
#
# models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
# 其他类似
#
# startswith,istartswith, endswith, iendswith,
# order by
#
# models.Tb1.objects.filter(name=''seven'').order_by(''id'') # asc
# models.Tb1.objects.filter(name=''seven'').order_by(''-id'') # desc
# group by
#
# from django.db.models import Count, Min, Max, Sum
# models.Tb1.objects.filter(c1=1).values(''id'').annotate(c=Count(''num''))
# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
# limit 、offset
#
# models.Tb1.objects.all()[10:20]
# regex正则匹配,iregex 不区分大小写
#
# Entry.objects.get(title__regex=r''^(An?|The) +'')
# Entry.objects.get(title__iregex=r''^(an?|the) +'')
# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)
# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)
# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)
# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
# hour
#
# Event.objects.filter(timestamp__hour=23)
# Event.objects.filter(time__hour=5)
# Event.objects.filter(timestamp__hour__gte=12)
# minute
#
# Event.objects.filter(timestamp__minute=29)
# Event.objects.filter(time__minute=46)
# Event.objects.filter(timestamp__minute__gte=29)
# second
#
# Event.objects.filter(timestamp__second=31)
# Event.objects.filter(time__second=2)
# Event.objects.filter(timestamp__second__gte=31)
进阶操作
3、其他操作(执行原生SQL)
# 执行原生SQL
1.执行自定义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()
2.使用extra方法
#
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# Entry.objects.extra(select={''new_id'': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=[''headline=%s''], params=[''Lennon''])
# Entry.objects.extra(where=["foo=''a'' OR bar = ''a''", "baz = ''a''"])
# Entry.objects.extra(select={''new_id'': "select id from tb where id > %s"}, select_params=(1,), order_by=[''-nid''])
3.使用raw方法
解释:执行原始sql并返回模型
说明:依赖model多用于查询
用法:
book = Book.objects.raw("select * from hello_book")
for item in book:
print(item.title)
https://www.cnblogs.com/413xiaol/p/6504856.html
# F
#
# from django.db.models import F
# models.Tb1.objects.update(num=F(''num'')+1)
# Q
#
# 方式一:
# Q(nid__gt=10)
# Q(nid=8) | Q(nid__gt=10)
# Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=''root'')
# 方式二:
# con = Q()
# q1 = Q()
# q1.connector = ''OR''
# q1.children.append((''id'', 1))
# q1.children.append((''id'', 10))
# q1.children.append((''id'', 9))
# q2 = Q()
# q2.connector = ''OR''
# q2.children.append((''c1'', 1))
# q2.children.append((''c1'', 10))
# q2.children.append((''c1'', 9))
# con.add(q1, ''AND'')
# con.add(q2, ''AND'')
#
# models.Tb1.objects.filter(con)
四、ORM连表操作
我们在学习django中的orm的时候,我们可以把一对多,多对多,分为正向和反向查找两种方式。
正向查找:ForeignKey在 UserInfo表中,如果从UserInfo表开始向其他的表进行查询,这个就是正向操作,反之如果从UserType表去查询其他的表这个就是反向操作。
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
正向连表操作总结:
所谓正、反向连表操作的认定无非是Foreign_Key字段在哪张表决定的,
Foreign_Key字段在哪张表就可以哪张表使用Foreign_Key字段连表,反之没有Foreign_Key字段就使用与其关联的 小写表名;
1对多:对象.外键.关联表字段,values(外键字段__关联表字段)
多对多:外键字段.all()
反向连表操作总结:
通过value、value_list、fifter 方式反向跨表:小写表名__关联表字段
通过对象的形式反向跨表:小写表面_set().all()
data: JSON.stringify({
"table": "Functions",
"action": "select_hosts",
"db_type": data_type
}),
# 添加权限时 select标签 联动 选择数据
permit_option_dict = {
"DB_info": {"actions": {
"select_db_type": {"args": [''select_db_type''], "filter": ["database_type"],
"values": [''id'', ''host'', ''port'', ''instance_nikename'']},
"unique_alias": {"args": [''database_type'', "unique_alias"],
"filter": ["database_type", "instance_nikename__icontains"],
"values": [''id'', ''host'', ''port'', ''instance_nikename'']},
}},
"Functions": {"actions": {
"select_hosts": {"args": ["db_type"], "filter": ["sql_type"], "values": [''id'', ''sql'']},
"uniquefunction": {"args": [''select_db_type'', "uniquefunction"], "filter": ["sql_type", "sql__icontains"],
"values": [''id'', ''sql'']}
}
}
}
class Linkage(object): # 根据配置返回数据库数据
def __init__(self, request, model):
self.data = json.loads(request.body)
self.model = model
self.action = self.data.get("action")
self.table = self.data.get(''table'')
def get_data(self):
self.current_option_table = permit_option_dict.get(self.table).get("actions").get(self.action) # 当前操作的表
self.current_args_list = self.current_option_table.get(''args'') # request传来的参数有哪些
self.current_sql_value = self.current_option_table.get(''values'') # query_set.value(值)
self.current_args_filter_args = self.current_option_table.get(''filter'')
self.current_args_filter_value = [self.data.get(i) for i in self.current_args_list]
self.filter = dict(zip(self.current_args_filter_args, self.current_args_filter_value))
data = list(getattr(self.model, self.table).objects.filter(**self.filter).values(*self.current_sql_value))
return json.dumps(data)
根据前端参数,返回不同数据库结果
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
1、1对多
如果A表的1条记录对应B表中N条记录成立,两表之间就是1对多关系;在1对多关系中 A表就是主表,B表为子表,ForeignKey字段就建在子表;
如果B表的1条记录也对应A表中N条记录,两表之间就是双向1对多关系,也称为多对多关系;
在orm中设置如果 A表设置了外键字段user=models.ForeignKey(''UserType'')到B表(注意外键表名加引号)
就意味着 写在写A表的B表主键, (一列),代表B表的多个(一行)称为1对多,
查询
总结:利用orm获取 数据库表中多个数据
获取到的数据类型本质上都是 queryset类型,
类似于列表,
内部有3种表现形式(对象,字典,列表)
modle.表名.objects.all()
modle.表名.objects.values()
modle.表名.objects.values()
跨表
正操作
所以表间只要有外键关系就可以一直点下去。。。点到天荒地老
所以可以通过obj.外键.B表的列表跨表操作(注意!!orm连表操作必须选拿单个对象,不像SQL中直接表和表join就可以了)
print(obj.cls.title)
foreignkey字段在那个表里,那个表里一个"空格"代表那个表的多个(一行)
class UserGroup(models.Model):
"""
部门 3
"""
title = models.CharField(max_length=32)
class UserInfo(models.Model):
"""
员工4
"""
nid = models.BigAutoField(primary_key=True)
user = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField(default=1)
# ug_id 1
ug = models.ForeignKey("UserGroup",null=True)
1. 在取得时候跨表
q = UserInfo.objects.all().first()
q.ug.title
2. 在查的时候就跨表了
UserInfo.objects.values(''nid'',''ug_id'')
UserInfo.objects.values(''nid'',''ug_id'',''ug__title'') #注意正向连表是 外键__外键列 反向是小写的表名
3. UserInfo.objects.values_list(''nid'',''ug_id'',''ug__title'')
反向连表:
反向操作无非2种方式:
1、通过对象的形式反向跨表:小写表面_set().all()
2、通过value和value_list方式反向跨表:小写表名__字段
1. 小写的表名_set 得到有外键关系的对象
obj = UserGroup.objects.all().first()
result = obj.userinfo_set.all() [userinfo对象,userinfo对象,]
2. 小写的表名 得到有外键关系的列 #因为使用values取值取得是字典的不是对象,所以需要 小写表名(外键表)__
v = UserGroup.objects.values(''id'',''title'')
v = UserGroup.objects.values(''id'',''title'',''小写的表名称'')
v = UserGroup.objects.values(''id'',''title'',''小写的表名称__age'')
3. 小写的表名 得到有外键关系的列
v = UserGroup.objects.values_list(''id'',''title'')
v = UserGroup.objects.values_list(''id'',''title'',''小写的表名称'')
v = UserGroup.objects.values_list(''id'',''title'',''小写的表名称__age'')
1对多自关联( 由原来的2张表,变成一张表! )
想象有第二张表,关联自己表中的 行
代码

class Comment(models.Model):
"""
评论表
"""
news_id = models.IntegerField() # 新闻ID
content = models.CharField(max_length=32) # 评论内容
user = models.CharField(max_length=32) # 评论者
reply = models.ForeignKey(''Comment'',null=True,blank=True,related_name=''xxxx'') #回复ID

2、 多对多:
1、自己写第3张关系表
ORM多对多查询:
女士表:
男生表:
男女关系表
多对跨表操作
#获取方少伟有染的女孩
obj=models.Boy.objects.filter(name=''方少伟'').first()
obj_list=obj.love_set.all()
for row in obj_list:
print(row.g.nike)
# 获取和苍井空有染的男孩
obj=models.Girl.objects.filter(nike=''苍井空'').first()
user_list=obj.love_set.all()
for row in user_list:
print(row.b.name)
多对多关系表 数据查找思路
1、找到该对象
2.通过该对象 反向操作 找到第三张关系表
3.通过第三张关系表 正向操作 找到 和该对象有关系对象
总结(只要对象1和对象2 中间有关系表建立了关系; 对象1反向操作 到关系表 ,关系表正向操作到对象2,反之亦然
2、第3张关系表不用写(m=models.ManyToManyField('' 要关联的表'') 自动生成 )
由于 DjangoORM中一个类名对应一张表,要想操作表就modles.类直接操作那张表,但使用ManyToManyField字段生成 “第三张”关系表怎么操作它呢?
答案:通过单个objd对象 间接操作
class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField(''Girl'',through="Love",through_fields=(''b'',''g'',))
class Girl(models.Model):
nick = models.CharField(max_length=32)
m = models.ManyToManyField(''Boy'')
正向操作: obj.m.all()


1 obj = models.Boy.objects.filter(name=''方少伟'').first()
2 print(obj.id,obj.name)
3 obj.m.add(2)
4 obj.m.add(2,4)
5 obj.m.add(*[1,])
6
7 obj.m.remove(1)
8 obj.m.remove(2,3)
9 obj.m.remove(*[4,])
10
11 obj.m.set([1,])
12
13 q = obj.m.all()
14 # [Girl对象]
15 print(q)
16 obj = models.Boy.objects.filter(name=''方少伟'').first()
17 girl_list = obj.m.all()
18
19 obj = models.Boy.objects.filter(name=''方少伟'').first()
20 girl_list = obj.m.all()
21 girl_list = obj.m.filter(nick=''小鱼'')
22 print(girl_list)
23
24 obj = models.Boy.objects.filter(name=''方少伟'').first()
25 obj.m.clear()
反向操作 :obj.小写的表名_set
多对多和外键跨表一样都是 小写的表名_set
3、既自定义第三张关系表 也使用ManyToManyField(''Boy'')字段(杂交类型)
ManyToManyField()字段创建第3张关系表,可以使用字段跨表查询,但无法直接操作第3张表,
自建第3表关系表可以直接操作,但无法通过字段 查询,我们可以把他们结合起来使用;
作用:
1、既可以使用字段跨表查询,也可以直接操作第3张关系表
2、obj.m.all() 只有查询和清空 方法
class UserInfo(AbstractUser):
"""
用户信息
"""
nid = models.BigAutoField(primary_key=True)
nickname = models.CharField(verbose_name=''昵称'', max_length=32)
telephone = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name=''手机号码'')
avatar = models.FileField(verbose_name=''头像'', upload_to=''upload/avatar/'')
create_time = models.DateTimeField(verbose_name=''创建时间'',auto_now_add=True)
fans = models.ManyToManyField(verbose_name=''粉丝们'',
to=''UserInfo'',
through=''UserFans'',
through_fields=(''user'', ''follower''))
def __str__(self):
return self.username
class UserFans(models.Model):
"""
互粉关系表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey(verbose_name=''博主'', to=''UserInfo'', to_field=''nid'', related_name=''users'')
follower = models.ForeignKey(verbose_name=''粉丝'', to=''UserInfo'', to_field=''nid'', related_name=''followers'')
class Meta:
unique_together = [
(''user'', ''follower''),
]
through=''UserFans''指定第3张关系表的表名
through_fields 指定第3张关系表的字段
class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField(''Girl'',through="Love",through_fields=(''b'',''g'',))
# 查询和清空
class Girl(models.Model):
nick = models.CharField(max_length=32)
# m = models.ManyToManyField(''Boy'')
class Love(models.Model):
b = models.ForeignKey(''Boy'')
g = models.ForeignKey(''Girl'')
class Meta:
unique_together = [
(''b'',''g''),
外键反向查找别名(方便反向查找)
在写ForeignKey字段的时候,如果想要在反向查找时不使用默认的 小写的表名_set,就在定义这个字段的时间加related参数!
related_name、related_query_name 字段=什么别名 反向查找时就使用什么别名!
反向查找:
设置了related_query_name 反向查找时就是obj.别名_set.all()保留了_set
related_query_name
from django.db import models
class Userinfo(models.Model):
nikename=models.CharField(max_length=32)
username=models.CharField(max_length=32)
password=models.CharField(max_length=64)
sex=((1,''男''),(2,''女''))
gender=models.IntegerField(choices=sex)
''''''把男女表混合在一起,在代码层面控制第三张关系表的外键关系 ''''''
#写到此处问题就来了,原来两个外键 对应2张表 2个主键 可以识别男女
#现在两个外键对应1张表 反向查找 无法区分男女了了
# object对象女.U2U.Userinfo.set object对象男.U2U.Userinfo.set
#所以要加related_query_name对 表中主键 加以区分
#查找方法
# 男 obj.a._set.all()
# 女:obj.b._set.all()
class U2U(models.Model):
b=models.ForeignKey(Userinfo,related_query_name=''a'')
g=models.ForeignKey(Userinfo,related_query_name=''b'')
related_name
反向查找:
设置了relatedname就是 反向查找时就说 obj.别名.all()
from django.db import models
class Userinfo(models.Model):
nikename=models.CharField(max_length=32)
username=models.CharField(max_length=32)
password=models.CharField(max_length=64)
sex=((1,''男''),(2,''女''))
gender=models.IntegerField(choices=sex)
''''''把男女表混合在一起,在代码层面控制第三张关系表的外键关系 ''''''
#写到此处问题就来了,原来两个外键 对应2张表 2个主键 可以识别男女
#现在两个外键对应1张表 反向查找 无法区分男女了了
# object对象女.U2U.Userinfo.set object对象男.U2U.Userinfo.set
#所以要加related_query_name设置反向查找命名对 表中主键 加以区分
#查找方法
# 男 obj.a.all()
# 女:obj.b.all()
class U2U(models.Model):
b=models.ForeignKey(Userinfo,related_name=''a'')
g=models.ForeignKey(Userinfo,related_name=''b'')
操作
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
#查找 ID为1男孩 相关的女孩
boy_obj=models.Userinfo.objects.filter(id=1).first()
res= boy_obj.boy.all()#得到U2U的对象再 正向跨表
#原来跨表 boy_obj.小写表名.all()
# 现在设置了related_name(别名) 直接res= boy_obj.boy.all()跨表
for obj in res:
print(obj.g.nikename)
return HttpResponse(''OK'')
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
#查找 ID为1男孩 相关的女孩
boy_obj=models.Userinfo.objects.filter(id=1).first()
res= boy_obj.boy.all()#得到U2U的对象再 正向跨表
#原来跨表 boy_obj.小写表名.all()
# 现在设置了related_name(别名) 直接res= boy_obj.boy.all()跨表
for obj in res:
print(obj.g.nikename)
return HttpResponse(''OK'')
class Userinfo(models.Model):
nikename=models.CharField(max_length=32)
username=models.CharField(max_length=32)
password=models.CharField(max_length=64)
sex=((1,''男''),(2,''女''))
gender=models.IntegerField(choices=sex)
m=models.ManyToManyField(''Userinfo'')
查找方法
def index(request):
# 多对多自关联 之通过男士查询女生
boy_obj=models.Userinfo.objects.filter(id=4).first()
res=boy_obj.m.all()
for row in res:
print(row.nikename)
return HttpResponse(''OK'')
#多对多自关联 之通过女士查询男生
girl_obj=models.Userinfo.objects.filter(id=4).first()
res=girl_obj.userinfo_set.all()
for obj in res:
print(obj.nikename)
return HttpResponse(''OK'')
多对多自关联特性:
ManyToManyField生成的第三张表
五、浅谈ORM查询性能
普通查询
obj_list=models.Love.objects.all()
for row in obj_list: #for循环10次发送10次数据库查询请求
print(row.b.name)
这种查询方式第一次发送 查询请求每for循环一次也会发送查询请求
1、select_related:结果为对象 注意query_set类型的对象 都有该方法
原理: 查询时主动完成连表形成一张大表,for循环时不用额外发请求;
试用场景: 节省硬盘空间,数据量少时候适用相当于做了一次数据库查询;
obj_list=models.Love.objects.all().select_related(''b'')
for row in obj_list:
print(row.b.name)
2、prefetch_related:结果都对象是
原理:虽好,但是做连表操作依然会影响查询性能,所以出现prefetch_related
prefetch_related:不做连表,多次单表查询外键表 去重之后显示, 2次单表查询(有几个外键做几次1+N次单表查询,
适用场景:效率高,数据量大的时候试用
obj_list=models.Love.objects.all().prefetch_related(''b'')
for obj in obj_list:
print(obj.b.name)
3、update()和对象.save()修改方式的性能PK
修改方式1
models.Book.objects.filter(id=1).update(price=3)
方式2
book_obj=models.Book.objects.get(id=1)
book_obj.price=5
book_obj.save()
执行结果:
(0.000) BEGIN; args=None
(0.000) UPDATE "app01_book" SET "price" = ''3.000'' WHERE "app01_book"."id" = 1; args=(''3.000'', 1)
(0.000) SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."date", "app01_book"."publish_id", "app01_book"."classify_id" FROM "app01_book" WHERE "app01_book"."id" = 1; args=(1,)
(0.000) BEGIN; args=None
(0.000) UPDATE "app01_book" SET "title" = ''我的奋斗'', "price" = ''5.000'', "date" = ''1370-09-09'', "publish_id" = 4, "classify_id" = 3 WHERE "app01_book"."id" = 1; args=(''我的奋斗'', ''5.000'', ''1370-09-09'', 4, 3, 1)
[31/Aug/2017 17:07:20] "GET /fandq/ HTTP/1.1" 200 2
结论:
update() 方式1修改数据的方式,比obj.save()性能好;
六、分组和聚合查询
1、aggregate(*args,**kwargs) 聚合函数
通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
from django.db.models import Avg,Sum,Max,Min
#求书籍的平均价
ret=models.Book.objects.all().aggregate(Avg(''price''))
#{''price__avg'': 145.23076923076923}
#参与西游记著作的作者中最老的一位作者
ret=models.Book.objects.filter(title__icontains=''西游记'').values(''author__age'').aggregate(Max(''author__age''))
#{''author__age__max'': 518}
#查看根哥出过得书中价格最贵一本
ret=models.Author.objects.filter(name__contains=''根'').values(''book__price'').aggregate(Max(''book__price''))
#{''book__price__max'': Decimal(''234.000'')}
2、annotate(*args,**kwargs) 分组函数
#查看每一位作者出过的书中最贵的一本(按作者名分组 values() 然后annotate 分别取每人出过的书价格最高的)
ret=models.Book.objects.values(''author__name'').annotate(Max(''price''))
# < QuerySet[
# {''author__name'': ''吴承恩'', ''price__max'': Decimal(''234.000'')},
# {''author__name'': ''吕不韦'',''price__max'': Decimal(''234.000'')},
# {''author__name'': ''姜子牙'', ''price__max'': Decimal(''123.000'')},
# {''author__name'': ''亚微'',price__max'': Decimal(''123.000'')},
# {''author__name'': ''伯夷 '', ''price__max'': Decimal(''2010.000'')},
# {''author__name'': ''叔齐'',''price__max'': Decimal(''200.000'')},
# {''author__name'': ''陈涛'', ''price__max'': Decimal(''234.000'')},
# {''author__name'': ''高路川'', price__max'': Decimal(''234.000'')}
# ] >
#查看每本书的作者中最老的 按作者姓名分组 分别求出每组中年龄最大的
ret=models.Book.objects.values(''author__name'').annotate(Max(''author__age''))
# < QuerySet[
# {''author__name'': ''吴承恩'', ''author__age__max'': 518},
# {''author__name'': ''张X'', ''author__age__max'': 18},
# { ''author__name'': ''张X杰'', ''author__age__max'': 56},
# {''author__name'': ''方X伟'', ''author__age__max'': 26},
# {''author__name'': ''游X兵'', ''author__age__max'': 35},
# {''author__name'': ''金庸'', ''author__age__max'': 89},
# { ''author__name'': ''X涛'', ''author__age__max'': 27},
# {''author__name'': ''高XX'', ''author__age__max'': 26}
# ] >
#查看 每个出版社 出版的最便宜的一本书
ret=models.Book.objects.values(''publish__name'').annotate(Min(''price''))
# < QuerySet[
# {''publish__name'': ''北大出版社'',''price__min'': Decimal(''67.000'')},
# {''publish__name'': ''山西出版社'',''price__min'': Decimal(''34.000'')},
# {''publish__name'': ''河北出版社'', ''price__min'': Decimal(''123.000'')},
# {''publish__name'': ''浙江出版社'', ''price__min'': Decimal(''2.000'')},
# {''publish__name'': ''湖北出版社'', ''price__min'': Decimal(''124.000'')},
# {''publish__name'': ''湖南出版社'',price__min'': Decimal(''15.000'')}
# ] >
七、F查询与Q查询
仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:
1、F 可以获取对象中的字段的属性(列),并对其进行操作;
from django.db.models import F,Q
#F 可以获取对象中的字段的属性(列),并且对其进行操作;
models.Book.objects.all().update(price=F(''price'')+1) #对图书馆里的每一本书的价格 上调1块钱
2、Q多条件组合查询
Q()可以使orm的fifter()方法支持, 多个查询条件,使用逻辑关系(&、|、~)包含、组合到一起进行多条件查询;
语法:
fifter(Q(查询条件1)| Q(查询条件2))
fifter(Q(查询条件2)& Q(查询条件3))
fifter(Q(查询条件4)& ~Q(查询条件5))
fifter(Q(查询条件6)| Q(Q(查询条件4)& ~ Q(Q(查询条件5)& Q(查询条件3)))包含
from django.db.models import F,Q
1、F 可以获取对象中的字段的属性(列),并且对其进行操作;
# models.Book.objects.all().update(price=F(''price'')+1)
2、Q多条件组合查询
#如果 多个查询条件 涉及到逻辑使用 fifter(,隔开)可以表示与,但没法表示或非得关系
#查询 书名包含作者名的书
book=models.Book.objects.filter(title__icontains=''伟'',author__name__contains=''伟'').values(''title'')
#如何让orm 中得 fifter 支持逻辑判断+多条件查询? Q()登场
book=models.Book.objects.filter(Q(title__icontains=''伟'') & Q(author__name__contains=''伟'')).values(''title'')
book=models.Book.objects.filter(Q(author__name__contains=''伟'') & ~Q(title__icontains=''伟'')).values(''title'')
#多条件包含组合查询
#查询作者姓名中包含 方/少/伟/书名包含伟3字 并且出版社地址以山西开头的书
book=models.Book.objects.filter(
Q(
Q(author__name__contains=''方'') |
Q(author__name__contains=''少'') |
Q(title__icontains=''伟'')|
Q(author__name__contains=''伟'')
)
&
Q(publish__addr__contains=''山西'')
).values(''title'')
print(book)
return HttpResponse(''OK'')
注意:Q查询条件和非Q查询条件混合使用注意,不包Q()的查询条件一点要放在Q(查询条件)后面
八、Django自带ContentType表
首先声明本文介绍的ContentType不是http协议中请求头里Content Type,而是Django程序启动后自带的一张表;
INSTALLED_APPS = [
''django.contrib.admin'',
''django.contrib.auth'',
''django.contrib.contenttypes'',
''django.contrib.sessions'',
''django.contrib.messages'',
''django.contrib.staticfiles'',
''app01.apps.App01Config'',
]
setings.py配置文件
1、ContentType表内容介绍
ContentType表记录了Django程序的所有APP下model中的表名、和所在app的名称;
2、应用场景:
2.1 通过ContentType中的app名称和表名,查找到Django model中所有表;
from django.shortcuts import render,HttpResponse
from django.contrib.contenttypes.models import ContentType
#在Django默认设置app,contrib.contenttypes下中models 导入ContentType类(表)
def test(request):
c=ContentType.objects.get(app_label=''app01'',model=''boy'')
print(c)
#boy
model_class=c.model_class()
print(model_class)
#app01.models.Boy
return HttpResponse(''OK'')
;
2.2 解决 1张表 同时 其他N张表建立外键,并且多个外键中只能选择1个,关系的复杂问题
场景1:你是一家在线教育的DBA,现有N种优惠券,每1种优惠券怎么分别对应 N门课程中的一1门课程,怎么设计表结构呢?
from django.db import models
from django.contrib.contenttypes.models import ContentType
class DegreeCourse(models.Model):
"""学位课程
ID 名称
学位课1
学位课2
"""
name = models.CharField(max_length=128, unique=True)
class Course(models.Model):
"""普通课程
ID 名称
普通课1
普通课2
"""
name = models.CharField(max_length=128, unique=True)
class Coupon(models.Model):
"""优惠券生成规则
ID 优惠券名称 content_type_id(表) object_id(表中数据ID)
通用 null null
满100-10 8 1
满200-30 8 2
满200-30 9 1
总结:
"""
name = models.CharField(max_length=64, verbose_name="活动名称")
brief = models.TextField(blank=True, null=True, verbose_name="优惠券介绍")
#course_type 代指哪张表
course_type = models.ForeignKey(ContentType,blank=True,null=True)
#代指对象ID
object_id=models.IntegerField(blank=True,null=True)
场景2 :学生 学习成绩如何要奖惩、 作业写得如何要奖惩、学习进度如何要奖惩、。。。。。。学生各种行为都要奖惩怎么设计表结构?
class Homework(models.Model):
"""
ID User Name score
吴昊 第一模块 30
吴昊 第二模块 80
吴昊 第三模块 100
"""
name = models.CharField(max_length=32)
score_choices = (
(100,''A''),
(80,''B''),
(60,''C''),
(30,''D''),
)
score = models.IntegerField(choices=score_choices)
user = models.ForeignKey(''User'')
class Record(models.Model):
"""
ID User Name score
吴昊 第一模块 10 5
吴昊 第二模块 8 10
"""
name = models.CharField(max_length=32)
score_choices = (
(100, ''A''),
(80, ''B'')
)
score = models.IntegerField(choices=score_choices)
class ScoreRecord(models.Model):
"""
ID Name 表 对象
作业太差 1
作业太好 1
看的太快 null 1
"""
name = models.CharField(max_length=32)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
# 对象ID
object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
3、content type 操作
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class DegreeCourse(models.Model):
"""学位课程
ID 名称
学位课1
学位课2
"""
name = models.CharField(max_length=128, unique=True)
#GenericRelation 自动连表查询
xx= GenericRelation(''Coupon'')
class Course(models.Model):
"""普通课程
ID 名称
普通课1
普通课2
"""
name = models.CharField(max_length=128, unique=True)
class Coupon(models.Model):
"""优惠券生成规则
ID 优惠券名称 content_type_id(表) object_id(表中数据ID)
通用 null null
满100-10 8 1
满200-30 8 2
满200-30 9 1
总结:
"""
name = models.CharField(max_length=64, verbose_name="活动名称")
brief = models.TextField(blank=True, null=True, verbose_name="优惠券介绍")
#course_type 代指哪张表 注意该字段必须为 content_type=
content_type = models.ForeignKey(ContentType,blank=True,null=True)
#代指对象ID
object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
#通过 contenttype 直接 创建 外键关系,不会生成额外的列,注意 (''content_type'',''object_id'') 和上面2字段保持一致
content_object=GenericForeignKey(''content_type'',''object_id'')
model
from django.shortcuts import render,HttpResponse
from django.contrib.contenttypes.models import ContentType
from app01 import models
def test(request):
# c=ContentType.objects.get(app_label=''app01'',model=''boy'')
# print(c)
# #boy
# model_class=c.model_class()
# print(model_class)
# #app01.models.Boy
#给学位课1,创建优惠券100
#方式1
#1、在学位课表中 ,找到学位课1
d1=models.DegreeCourse.objects.get(id=1)
#2、在ContentType找到学位课表
c1= ContentType.objects.get(app_label=''app01'',model=''degreecourse'')
#3 给学位课1,创建优惠券100
# models.Coupon.objects.create(name=''优惠券'',brief=''100'',content_type=c1,object_id=d1.id)
# 方式2
# d1 = models.DegreeCourse.objects.get(id=1)
# models.Coupon.objects.create(name=''优惠券'',brief=''100'',content_object=d1)
#当前课程都有哪些优惠券?
d1 = models.DegreeCourse.objects.get(id=1)
# 查询关联的所有优惠券
print(d1.xx.all())
v=models.DegreeCourse.objects.values(''name'',''xx__brief'',''xx__name'')
print(v)
return HttpResponse(''OK'')
视图
3.1 GenericForeignKey 创建
给学位课1,创建优惠券100
#给学位课1,创建优惠券100
#方式1
#1、在学位课表中 ,找到学位课1
d1=models.DegreeCourse.objects.get(id=1)
#2、在ContentType找到学位课表
c1= ContentType.objects.get(app_label=''app01'',model=''degreecourse'')
#3 给学位课1,创建优惠券100
models.Coupon.objects.create(name=''优惠券'',brief=''100'',content_type=c1,object_id=d1.id)
方式1
#course_type 代指哪张表 注意该字段必须为 content_type=
content_type = models.ForeignKey(ContentType,blank=True,null=True)
#代指对象ID
object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
#直接和contenttype 创建 外键关系,不会生成额外的列
content_object=GenericForeignKey(''content_type'',''object_id'')
d1 = models.DegreeCourse.objects.get(id=1)
models.Coupon.objects.create(name=''优惠券'',brief=''100'',content_object=d1)
return HttpResponse(''OK'')
3.2 GenericRelation 查询
当前课程都有哪些优惠券?
class DegreeCourse(models.Model):
"""学位课程
ID 名称
学位课1
学位课2
"""
name = models.CharField(max_length=128, unique=True)
#GenericRelation 自动连表查询
xx= GenericRelation(''Coupon'')
model
#当前课程都有哪些优惠券?
d1 = models.DegreeCourse.objects.get(id=1)
# 查询关联的所有优惠券
print(d1.xx.all())
v=models.DegreeCourse.objects.values(''name'',''xx__brief'',''xx__name'')
print(v)
九、补充
1.oder_by(-id):按照某种规则排序
2.exclude(字段):字段获取数据时排除
course_list = models.Course.objects.exclude(course_type=2)
3.按时间查询
Django的orm支持按时间查询数据,前提是你在models中设置了该字段为DateTimeField 以及该字段存储的数据类型为 python的datime时间类型。
提示:
如果在通过时间查询的时候出现 warning 在setings.py中设置如下:
USE_TZ = True
如果时间格式显示英文在setings.py中设置如下:
LANGUAGE_CODE = ''zh-Hans''
A.查询大于某个时间点产生的数据。(在某个时间点之后)
#gt:大于某个时间
now = datetime.datetime.now()
start = now-datetime.timedelta(hours=23,minutes=59,seconds=59)
#查询 前一天的数据
obj=models.TaskLog.objects.filter(date__gt=start)
print(obj)
B.大于等于某个时间点

import datetime
start_date = datetime.date(2018, 9, 5)
#gte:大于等于某个时间点
now = datetime.datetime.now()
start = now-datetime.timedelta(hours=23,minutes=59,seconds=59)
#查询 前一天的数据
obj=models.TaskLog.objects.filter(date__gte=start)
print(obj)

C.小于某个时间点(在某个时间点之前)

import datetime
start_date = datetime.date(2018, 9, 5)
#lt:小于某个时间点
now = datetime.datetime.now()
start = now-datetime.timedelta(hours=23,minutes=59,seconds=59)
#查询 2018年9月4日,之前产生的日志。
obj=models.TaskLog.objects.filter(date__lt=start)
print(obj)

D.小于等于某个时间点

import datetime
start_date = datetime.date(2018, 9, 5)
#lte:小于等于某个时间点
now = datetime.datetime.now()
start = now-datetime.timedelta(hours=23,minutes=59,seconds=59)
#查询 2018年9月4日当日以及当天之前产生的日志。
obj=models.TaskLog.objects.filter(date__lte=start)
print(obj)

E.range:查询某个明确时间段数据 (某个时间段)
import datetime
start_date = datetime.date(2018, 9, 5)
end_date = datetime.date(2018, 9,8)
#查询 2018年9月5日 ------- 2018年9月8日 期间产生的日志
obj=models.TaskLog.objects.filter(date__range=(start_date,end_date))
print(obj)
F.__year查询某年产生数据(例如:2018)
#查询2018年产生的日志
obj=models.TaskLog.objects.filter(date__year=2018)
print(obj)
G.__month查询 某月产生的数据(例:2018年9月)
#查询9月产生的数据
obj=models.TaskLog.objects.filter(date__year=2018,date__month=9)
print(obj)
H.__week_day查询某年、某月、星期几产生的数据(例如:2018年9月份 每个星期5)
#查询 某年 某月 周几 产生的数据
# 0-6表示:周1至周五
obj=models.TaskLog.objects.filter(date__year=2018,date__month=9,date__week_day=4).count()
print(obj)
I.查询某年、某月、某天产生的数据 (例:2018年9月10日)
obj=models.TaskLog.objects.filter(date__year=2018,date__month=9,date__day=10).count()
print(obj)
原贴:https://www.cnblogs.com/sss4/p/7070942.html
二龙湖浩哥:http://www.cnblogs.com/yuanchenqi/articles/6811632.html#3763280
银角大王:http://www.cnblogs.com/wupeiqi/articles/5246483.html
今天的关于Django ORM操作和django orm的操作的分享已经结束,谢谢您的关注,如果想了解更多关于Django - Model操作 和 ORM操作、Django - ORM操作、Django - 表与ORM操作、django -orm操作总结的相关知识,请在本站进行查询。
本文标签: