一、数据库表的创建
这里需要注意的是如果我们连接的是MySQL数据库,那么就需要我们自己预先创建好数据库,这里我们使用model操作不能够创建数据库,只能够创建相应的表结构。
models中与数据库中对应的关系
类名 -----> 数据表的表名(数据库中的表)
对象(相当于我们实例化上面的类,也就是我们使用语句添加数据) -----> 数据行(表中的一行行数据)
属性变量(可以通过对象获取到相应的属性如id,name...) -----> 字段 (表中的一列列的如id,name...)
属性值(=后面的一些约束字段等) -------> 约束条件
基本的结构
from django.db import models class userinfo(models.Model): # 如果没有models.AutoField,默认会创建一个id的自增列 username = models.CharField(max_length=32) # models.CharField 这个就是后面说的字段,括号里面的参数就是字段的参数 password = models.CharField(max_length=32) email = models.EmailField()
字段解释
1、models.AutoField 自增列 ---> int(11) 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。 2、models.BigAutoField 2、models.CharField 字符串类型 必须有 max_length 参数 表示的是字符的长度 3、models.BooleanField 布尔类型 ---> tinyint(1) 不能为空,Blank=True 4、models.ComaSeparatedIntegerField 用逗号分割的数字--->varchar 继承CharField,所以必须有 max_lenght 参数 5、models.DateField 日期类型 ---> date 对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。 6、models.DateTimeField 日期类型 ---> datetime 同DateField的参数 7、models.Decimal 十进制小数类型 ---> decimal 必须指定整数位max_digits和小数位decimal_places 8、models.EmailField 字符串类型(正则表达式邮箱)---> varchar 对字符串进行正则表达式,Django Admin以及ModelForm中提供验证机制 9、models.FloatField 浮点类型 ---> double 10、models.IntegerField 整形 11、models.BigIntegerField 长整形 integer_field_ranges ={ 'SmallIntegerField':(-32768,32767), 'IntegerField':(-2147483648,2147483647), 'BigIntegerField':(-9223372036854775808,9223372036854775807), 'PositiveSmallIntegerField':(0,32767), 'PositiveIntegerField':(0,2147483647), } 12、models.IPAddressField 字符串类型(ip4正则表达式) Django Admin以及ModelForm中提供验证 IPV4 机制 13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的) Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置报错 14、models.NullBooleanField 允许为空的布尔类型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 字符串类型 Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) 18、models.SmallIntegerField 数字 数据库中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 文本类型 20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串类型 正则表达式,Django Admin以及ModelForm中提供验证 URL 22、models.BinaryField 二进制 23、models.ImageField 字符串 路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) 24、models.FilePathField 字符串类型 Django Admin以及ModelForm中提供读取文件夹下文件的功能
字段中的一些参数
1、null=True 数据库中字段是否可以为空 2、blank=True django的Admin中添加数据时是否可允许空值 3、primary_key =False 主键,对AutoField设置主键后,就会代替原来的自增 id 列 4、auto_now 和 auto_now_add auto_now 自动创建---无论添加或修改,都是当前操作的时间 auto_now_add 自动创建---永远是创建时的时间 5、choices GENDER_CHOICE =( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 表示字符的长度 7、default 默认值 8、verbose_name Admin中字段的显示名称 9、name|db_column 数据库中的字段名称 10、unique=True 不允许重复,唯一性 11、db_index =True 数据库索引 12、editable=True 在Admin里是否可编辑 13、error_messages=None 错误提示 14、auto_created=False 自动创建 15、help_text 在Admin中提示帮助信息 16、validators=[] 17、upload-to
下面是关于数据库的一个示列图书管理系统。
这里面有:出版社,书籍,作者
这里我们可以知道一个出版社可以出版多个书籍,但是一个书籍只能有一个出版社。所以出版社和书籍是一对多的关系。
书籍和作者我们可以知道一本书可以有多个作者,一个作者可以写多本书,所以书籍和作者之间是多对多的关系。
一对多
class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) addr = models.CharField(max_length=128) # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher")
一对多我们只需要在对应关系的多的一个表中加入一个外键字段这个外键关联那个一的表也就是书籍关联出版社。
多对多的关系的创建
from django.db import models # Create your models here. # 图书管理系统, 书 作者 出版社 # 出版社 class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) addr = models.CharField(max_length=128) # 方式一 # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") # 这个在表里面会自动生成一个为publisher_id的字段 # 作者表 class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) # 告诉ORM 我这张表和book表是多对多的关联关系,ORM自动帮我生成了第三张表 book = models.ManyToManyField(to="Book") #这样会自动生成的表名为:book_author表,同时会有id、author_id、book_id这些字段 #同时我们在进行数据查询的时候不能够直接操作这个自动生成的表只有间接操作。 # # 方式二 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") # 作者表 class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) #自己创建第三张表创建第三张表来关联这两张表 class Author_Book(models.ManyToManyField): id = models.AutoField(primary_key=True) author = models.ForeignKey(to='Author') book = models.ForeignKey(to='Book') #自动在表中生成字段 author_id、book_id的字段。 #这个我们自己创建的第三方表我们可以直接操作,不同于自动创建的第三张表。 #这里我们还可以看出自己创建的第三方表我们可以自己再加一些字段到里面。 #而自动创建的第三方表,它的字段是固定。 #上面可以看出自己创建的第三方表比自动创建的第三方表好些 #第三种方式 # 书 class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) # 创建外键,关联publish publisher = models.ForeignKey(to="Publisher") # 作者 class Author(models.Model): name = models.CharField(max_length=32) # 通过through,through_fields来指定使用我创建的第三张表来构建多对多的关系 books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book",)) # 第一个字段(黄色部位): 多对多设置在哪一张表里就填这个表的表明, 第三张表通过什么字段找到这张表 就把这个字段写在前面 # 自己动手 创建作者和书关联的第三张表 # 此时 在ORM层面 class Author2Book(models.Model): id = models.AutoField(primary_key=True) # 作者id author = models.ForeignKey(to="Author") # 书id book = models.ForeignKey(to="Book") class Meta: # 建立唯一约束 unique_together = ("author", "book") # 没有这个就会出现一个这样除了id其他都一样的字符如下 # 这个就是联合起来唯一,就不会出现两行数据中author_id、book_id这个2个字段相同 id author_id book_id 1 1 1 2 1 1
上面的三种方式的各自特点:
第一种方式:
自动生成第三张表
第二种方式:
自己创建第三张表, 利用外键分别关联作者和书
关联查询比较麻烦,因为没办法使用ORM提供的便利方法(相对于第一种)
第三种方式:
自己创建第三张表,使用ORM 的ManyToManyFiled()
使用此种方式创建多对多表的时候,没有 add() remove() 等方法(相对于第一种)
如何选用那种方式?
1、 如果你第三张表没有额外的字段,就用第一种
2、 如果你第三张表有额外的字段,就用第三种或第二种
选用第二种和第三种的场景。
相亲网站:当我们每一对相亲对象见面我们要设置时间这个时间据需要写在第三张表中
上面的表创建完后我们可以在当前项目的manage.py的同级目录下执行两个命令
1、python3 manage.py makemigrations
这个命令就是把我们对数据库中表的更改记录下来,并放在app目录下的migrations目录下
2、python3 manage.py migrate
这个是把上面记录下来的数据翻译成数据库语言,在数据库中执行相当于把更改后的数据平移到数据库中。
还有一种我们可以在pycharm下面完成上面操作如下:
这样会出来一个控制台只要在里面输入,makemigrations 和 migrate。和上面等同效果。这个还会出现提示输入。
Django 的ORM的一些操作。
必须会的几种操作
1、all() ----> 查询所有的结果,得到的是一个列表中元素是对象的返回值(下面统一叫对象列表) lis_obj = models.Author.objects.all() print('*'*10) print(type(lis_obj)) print('*' * 10) print(lis_obj) print('*' * 10) return HttpResponse("OK") #输出的结果为 ********** <class 'django.db.models.query.QuerySet'> ********** <QuerySet [<Author: Author object>, <Author: Author object>, <Author: Author object>]> ********** <class 'django.db.models.query.QuerySet'>这个和列表的操作差不多这里暂且叫做列表 使用all得到的返回值输出后,我们可以看到返回的是一个列表中元素为对象的返回值。 这里面的对象就是数据行一个对象代表查询的表的一行数据,通过对这个对象操作取到相应的字段的值 如: print(lis_obj[0].name) (在views.py中的使用) 返回的是Author表中第一行数据中字段为name的数据。这里的操作符合python的操作 lis_obj[0]表示取lis_obj列表中的第一个对象,lis_obj[0].name对象中的name属性值 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()
返回的是具体对象的方法有
get() :
first() :
last()
返回布尔值的方法有
exists()
返回数字的方法有
count()
特殊的QuerySet
values() 返回是一个字典为元素的列表(字段为key,字段的值为value)这个方法只能在对象列表(列表中的元素为对象)中使用
values_list() 返回是一个元组为元素的列表(只返回字段的value,没有key所以只能按顺序取)
单表查询双下划线
models.class_name.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.class_name.objects.filter(id__lt=10) # 获取小于10的值 models.class_name.objects.filter(id__lte=10) # 获取小于等于10的值 models.class_name.objects.filter(id__gt=2) # 获取大于2的值 models.class_name.objects.filter(id__gte=2) # 获取大于等于2的值 models.class_name.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.class_name.objects.exclude(id__in=[11, 22, 33]) # not in models.class_name.objects.filter(name__contains="ven") # 获取name字段包含"ven"的 models.class_name.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.class_name.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(外键)操作
正向查找
对象跨表查找 在app下的models class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) # addr = models.CharField(max_length=128) # 方式一 # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") 在app下的views def test(request): book_obj = models.Book.objects.first() # 找到的是书籍表中的第一本书的对象 print(book_obj.publisher) # 找到这本书关联的出版社对象,获取跨表关联的对象 print(book_obj.publisher.name) # 使用出版社对象获取里面的属性name return HttpResponse("OK") 字段查找(跨表) 关联字段__字段 print(models.Book.objects.values_list('publisher__id')) print(models.Book.objects.values('publisher__id'))
上面的查找只能从有Foreignkey字段的表中跨表查找,不能够从被关联的表中反向查找
反向操作
# 这里书籍和出版社是多对一的关系 # obj.表名_set # publisher_obj = models.Publisher.objects.first() # 得到第一个出版社的对象 # books = publisher_obj.book_set.all() #获取这个出版社对象所有的书籍对象 # title = books.values_list('title') # 获取该出版社所有书籍的名字返回的是一个元素为元组的列表 # print(title) # 表名__字段 # titles = models.Publisher.objects.values_list("book__title")
反向查找的时候我们还可以在设置外键的时候加上一个字段related_name='自己这张表起一个名字' 这个名字是代替表名_set()
查询语句为:publisher_obj = models.Publisher.objects.first() # 得到第一个出版社的对象
ret = publisher_obj.books.all() 通过我们的别名直接在对象中通过.别名.all()得到所有关联的列表对象。
多对多关系(ManyToManyFiled)
"关联管理器"是一对多和多对多关联上下文中使用的管理器
存在的两种情况:
1.外键关系的反向查询
2.多对多关联关系
多对多的一些方法
create()
通过一个现有对象创建一个关联的对象,
如:用书和作者这个是多对多关系,我们用现有的作者来创建一本新的书并把两者关联起来。
相当于我们现在书的列表中创建一个书的数据,在在第三张关联的表中把这本书合 作者关联起来。
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象
添加一本书
models.Author.objects.first().book_set.create(title="学习go语言", publish_id=1)
上面就是添加一本书这本书关联了第一个作者和关联id为的出版社。
后面创建的书书里面有什么字段就写什么字段。
add()
把指定的model对象添加到关联对象集中
author_objs = models.Author.objects.get(id=3) 查找到id等于3的作者的所有对象
models.Book.objects.first().author_set.add(author_objs) 这里的意思把上面的作者对象和第一本书关联
如果关联多个的话。
author_objs = models.Author.objects.filter(id__lt=3) 查找到id小于3的作者的所有对象
models.Book.objects.first().author_set.add(*author_objs) 这里的意思把上面的所有的作者对象和第一本书关联
直接添加id
models.Book.objects.first().authors.add(*[1, 2]) 直接把作者的id关联
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时存在。
应为默认这项是不能为空的,当我们去除关联关系时,那ForeigKey这项就是空了,就会和默认不为空有冲突就会报错。
外键反向查找别名(方便反向查找)
在写ForeignKey字段的时候,如果想要在反向查找时不使用默认的 小写的表名_set,就在定义这个字段的时间加related参数!
related_name=别名, 反向查找的时候就用obj.别名.all()查找
related_query_name=别名 反向查找的时候就用obj.别名_set.all()查找
示列
class Book(models.Model): title = models.CharField(max_length=64, null=False, unique=True) publisher = models.ForeignKey(to="Publisher") def __str__(self): return self.title class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) book = models.ManyToManyField(to="Book", related_query_name='author') def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=64, null=False, unique=True) publisher = models.ForeignKey(to="Publisher") def __str__(self): return self.title class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=16, null=False, unique=True) book = models.ManyToManyField(to="Book", related_name='author') def __str__(self): return self.name
实现
# related_name obj = models.Author.objects.filter(id=1).first() print(obj1.author.all()) # related_query_name obj = models.Book.objects.get(id=1) print(obj.author_set.all())
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()性能好;
聚合查询和分组查询
聚合
from django.db.models import Avg,Sum,Max,Min
avg_book = models.Book.objects.all().aggregate(Avg('price'),Min('price')) # 所有书籍的平均价格,和最小的价格。这个里面有多个求值
这个得到的是一个字典{'price__avg': 算出来的平均值,'price__mix':Decimal('19.90')}
上面我们也可以给这个起名字
avg_book = models.Book.objects.all().aggregate(a = Avg('price'),Min('price'))
这个得到的是一个字典{'a': 算出来的平均值,'price__mix':Decimal('19.90')}
分组
from django.db.models import Avg,Sum,Max,Min,Count
一、统计一本书它的作者个数
book_list_obj = models.Book.objects.all().annotate(author_num=Count("author"))
上面是以每本书作为分组,统计每一本书的作者数量,在这个得到一个列表里面的元素是每一本书的对象,且这个对象比原先多了一个author_num属性
for obj in book_list_obj:
print(obj.title,obj.author_num) 这个输出的是表中每一本书的名字以及这本书有多少作者。
我们也可以得到一个列表列表中的元素为字典的返回值
book_list_dic = models.Book.objects.all().annotate(author_num=Count("author")) .values('title','author_num')
字典中的键只有'title'和'author_num'。
二、统计出每个出本社卖的最便宜的书的价格
publisher_list_obj = models.Publisher.objects.annotate(min_price=Min("book__price"))
一每一个出版社作为分组,上面的book__price是跨表查询书的价格
字典微元素的列表返回值
publisher_list_obj = models.Publisher.objects.annotate(min_price=Min("book__price")).value()
三、统计作者数目大于一的书籍
print(models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1) ) 输出的是一个元素为对象的列表
models.Book.objects.annotate(author_num=Count("author"))这个表示以书为分组找到所有的书有多少作者
.filter(author_num__gt=1)这个表示筛选条件山选出书的作者数目大于一
四、根据一本图书作者数量的多少对查询集 QuerySet进行排序
print(models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")) 输出的是一个元素为对象的列表
五、查询各个作者出的书的总价格
print(models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")) 输出的是元素为字典的列表
F查询和Q查询
F查询
1、查询评书的卖出大于库存的书籍
from django.db.models import F
print(models.Book.objects.filter(sale__gt=F('repertory')).values()) #得到的是一个元素为字典的列表
上面的黄色部位就是卖出的大于库存的。
2、Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作
models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
3、修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)
4、给每一本书的名字后面加上"第一版"
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F("title"), Value("第一版")))
Q查询
一、查询书的卖出卖出数量大于1000,或者价格小于100的所有书
from django.db.models import Q
models.Book.objects.filter(Q(sale__gt=1000) | Q(price__lt=1000))
二、Q查询和字段查询同时存在时,字段查询要放在Q查询后面
models.Book.objects.filter(Q(sale__gt=1000) | Q(price__lt=1000),title__contains='小黑')
三、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)))包含
上面就是Q里面也可以包含Q
Django ORM执行原生SQL
1.使用extra方法 解释:结果集修改器,一种提供额外查询参数的机制 说明:依赖model模型 用在where后: Book.objects.filter(publisher_id="1").extra(where=["title='python学习1'"]) 用在select后 Book.objects.filter(publisher_id="1").extra(select={"count":"select count(*) from hello_book"}) 2.使用raw方法 解释:执行原始sql并返回模型 说明:依赖model多用于查询 用法: book = Book.objects.raw("select * from hello_book") for item in book: print(item.title) 3.执行自定义SQL 解释:利用游标执行 导入:from django.db import connection 说明:不依赖model 用法: from django.db import connection cursor = connection.cursor() #插入 cursor.execute("insert into hello_author(name) values('xiaol')") #更新 cursor.execute("update hello_author set name='xiaol' where id=1") #删除 cursor.execute("delete from hello_author where name='xiaol'") #查询 cursor.execute("select * from hello_author") #返回一行 raw = cursor.fetchone() print(raw) # #返回所有 # cursor.fetchall()
QuerySet方法大全
################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 获取所有的数据对象 def filter(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def exclude(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def select_related(self, *fields) 性能相关:表之间进行join连表操作,一次性获取关联的数据。 总结: 1. select_related主要针一对一和多对一关系进行优化。 2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。 def prefetch_related(self, *lookups) 性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。 总结: 1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。 2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。 def annotate(self, *args, **kwargs) # 用于实现聚合group by查询 from django.db.models import Count, Avg, Max, Min, Sum v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 def distinct(self, *field_names) # 用于distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct进行去重 def order_by(self, *field_names) # 用于排序 models.UserInfo.objects.all().order_by('-id','age') def 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']) def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #仅取某个表中的数据 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') def using(self, alias): 指定使用的数据库,参数为别名(setting中的设置) ################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # ################################################## def raw(self, raw_query, params=None, translations=None, using=None): # 执行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其他表') # 为原生SQL设置参数 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 将获取的到列名转换为指定列名 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库 models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生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() # fetchall()/fetchmany(..) def values(self, *fields): # 获取每行数据为字典格式 def values_list(self, *fields, **kwargs): # 获取每行数据为元祖 def dates(self, field_name, kind, order='ASC'): # 根据时间进行某一部分进行去重查找并截取指定内容 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) # order只能是:"ASC" "DESC" # 并获取转换后的时间 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC') def datetimes(self, field_name, kind, order='ASC', tzinfo=None): # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo时区对象 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """ def none(self): # 空QuerySet对象 #################################### # METHODS THAT DO DATABASE QUERIES # #################################### def aggregate(self, *args, **kwargs): # 聚合函数,获取字典类型聚合结果 from django.db.models import Count, Avg, Max, Min, Sum result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) ===> {'k': 3, 'n': 4} def count(self): # 获取个数 def get(self, *args, **kwargs): # 获取单个对象 def create(self, **kwargs): # 创建对象 def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的个数 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10) def get_or_create(self, defaults=None, **kwargs): # 如果存在,则获取,否则,创建 # defaults 指定创建时,其他字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) def update_or_create(self, defaults=None, **kwargs): # 如果存在,则更新,否则,创建 # defaults 指定创建时或更新时的其他字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) def first(self): # 获取第一个 def last(self): # 获取最后一个 def in_bulk(self, id_list=None): # 根据主键ID进行查找 id_list = [11,21,31] models.DDD.objects.in_bulk(id_list) def delete(self): # 删除 def update(self, **kwargs): # 更新 def exists(self): # 是否有结果
Django终端打印SQL语句
在Django项目的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', }, } }
在Python脚本中调用Django环境
自manage.py的目录下创建一个.py的文件
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() from app01 import models books = models.Book.objects.all() print(books)
黄色部位BMS的是项目名称,app01就是我们写ORM的那个app名字。
批量创建数据:
from app import views objs = [models.Book(title="沙河{}".format(i)) for i in range(1500)] # 在数据库中批量创建, 10次一提交 models.Book.objects.bulk_create(objs, 10)