ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Django模型层:单表、多表操作、F与Q查询

2020-07-03 19:01:35  阅读:198  来源: 互联网

标签:__ 多表 Django filter objects 单表 obj 查询 book


DJango模型层

单表操作

使用有几步:

  1. settings.py中配置连接数据库的地址,端口
  2. 在init.py中使用pymysql
  3. 在models.py里写类,一个类对应一个表,写属性
  4. 数据库迁移命令,第一个命令是纪录,第二个命令才是真正的数据库同步
  5. 导入models到views,开始使用
# models.py
# 建立单表
from django.db import models
class User(models.Model):
	# 类名就是表名,必须继承models.Model
	name = models.CharField(max_length=32)
	# charfield必须指定最大长度,否则报错
	age = models.IntegerField()
	# 创建数字字段
	register_time = models.DateField(auto_now=True)
	# 创建日期对象,这个字段有两个重要的参数	
	# auto_now 每次操作数据的时候自动更新该字段为
	# auto_now_add,创建的时候纪录时间,只要不人为修改,就会一直不变

当没有创建主键字段(primary_key=True)的时候,orm会自动帮你创建一个名为id的主键字段

执行两条数据库迁移命令,接下来就可以在视图中或测试脚本中使用了

# views.py
from app01 import models
# 先从应用中导入模型
...

增加数据

# 第一种
res = models.User.objects.create(name='aaa',age=21,register_time='2020-02-22')
# models.表名.objects.create() 括号里面填字段,日期字段可以直接写日期也可以填一个日期对象
# 这个方法有一个返回值,就是被创建的对象本身

# 第二种
user_obj = models.User(name='aaa',age=21,register_time='2020-02-22')
user_obj.save()

删除数据

res = models.User.objects.filter(pk=2).delete()
# 查找当前表主键为2的字段,删除
user_obj = models.User.objects.filter(pk=2).first()
user_obj.delete()

修改数据

user_obj = models.User.objects.filter(pk=3).update(name='bbb')

orm其他的api

<1> all():                  查询所有结果
  
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
  
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
 
<5> order_by(*field):       对查询结果排序('-id')
  
<6> reverse():              对查询结果反向排序
  
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。
  
<9> first():                返回第一条记录
  
<10> last():                返回最后一条记录
  
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False
 
<12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<14> distinct():            从返回结果中剔除重复纪录

基于双下划线的模糊查询

Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)  # 大于
Book.objects.filter(price__lt=100)  # 小于
Book.objects.filter(price__gte=100)  # 大于等于
Book.objects.filter(price__lte=100)  # 小于等于
Book.objects.filter(price__range=[100,200]) 
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)

多表操作

表与表之间的关系有一对一,一对多,多对多

以图书,出版社,作者举例

一本图书只能有一个出版社,一个出版社出版多本书

  • 书----出版社 :一对多

一本书有多个作者,一个作者可以写多本书

  • 书----作者 : 多对多关系

作者与作者信息是一对一关系

img

创建外键

一对多

models.ForeignKey()

# 书与出版社一对多外键
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
# 创建外键字段publish,其中
# to:关联的表名
# to_field:要关联的表的字段名称,与publish表中的nid字段关联
# on_delete,删除表中的数据时,当前表与其关联的数据的行为
	# models.CASCADE,删除关联数据,与之关联也删除
    # models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
    # models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

一对一

models.OneToOneField()

# 作者信息与作者表,一对一关系
author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)
# 关联的表明:AuthorDetail,关联的字段nid,该字段唯一,删除表中的数据,authordetail中对应的author也删除

多对多

authors=models.ManyToManyField(to='Author')

orm多对多关系并没有真正的关联,声明一个ManyToMany字段后,orm会帮我们创建一张中间表

多表添加表纪录

一对多

方式1:
publish_obj=Publish.objects.get(nid=1)
book_obj=Book.objects.create(title="",publishDate="2012-12-12",price=100,publish=publish_obj)
  
方式2:
book_obj=Book.objects.create(title="",publishDate="2012-12-12",price=100,publish_id=1)

多对多

# 当前生成的书籍对象
book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
# 为书籍绑定的做作者对象
yuan=Author.objects.filter(name="yuan").first()
# 在Author表中主键为2的纪录
egon=Author.objects.filter(name="alex").first()
# 在Author表中主键为1的纪录

# 绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(yuan,egon)
#  将某些特定的 model 对象添加到被关联对象集合中。=======book_obj.authors.add(*[])

多对多关系常用api

book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除
# book_obj.authors.remove(*[])
book_obj.authors.clear()       #清空被关联对象集合
book_obj.authors.set()         #先清空再设置 

基于对象的跨表查询

查询两次,先拿到一个对象,再点再查一次得到结果

一对多

一对多的关系,外键字段建在多的一方,正向查询就是从有外键字段的这边查另一边:书表查出版社表

# 查询主键为1的书籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主键为1的书籍对象关联的出版社对象
print(book_obj.publish.city)

正向查询,直接使用点 . 即可

publish=Publish.objects.get(name="苹果出版社")
#publish.book_set.all() : 与苹果出版社关联的所有书籍对象集合
book_list=publish.book_set.all()    
for book_obj in book_list:
	print(book_obj.title)

反向查询,使用 要查询的表_set() 查询

一对一查询

正向,反向都用点方法

# 正向查询
egon=Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)
# 通过作者表查询作者信息表的电话号码
# 反向查询
# 查询所有住址在北京的作者的姓名
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
     print(obj.author.name)

多对多查询

# 眉所有作者的名字以及手机号
book_obj=Book.objects.filter(title="眉").first()
authors=book_obj.authors.all()
for author_obj in authors:
     print(author_obj.name,author_obj.authorDetail.telephone)
# 查询egon出过的所有书籍的名字
author_obj=Author.objects.get(name="egon")
book_list=author_obj.book_set.all()
#与egon作者相关的所有书籍
for book_obj in book_list:
    print(book_obj.title)

基于双下划线的跨表查询

使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止

一对多

表名__字段名

# 练习:  查询苹果出版社出版过的所有书籍的名字与价格(一对多)
# 正向查询 按字段:publish
queryResult=Book.objects.filter(publish__name="苹果出版社").values_list("title","price")
# 出版社表__出版社名

# 反向查询 按表名:book
queryResult=Publish.objects.filter(name="苹果出版社").values_list("book__title","book__price")
# 查询的本质一样,就是select from的表不一样

多对多

# 练习: 查询alex出过的所有书籍的名字(多对多)

# 正向查询 按字段:authors:
queryResult=Book.objects.filter(authors__name="yuan").values_list("title")

# 反向查询 按表名:book
queryResult=Author.objects.filter(name="yuan").values_list("book__title","book__price")

连续跨表案例

# 查询人民出版社出版过的所有书籍的名字以及作者的姓名

# 正向查询
queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
# 反向查询
queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")

F与Q查询

F查询

F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值

from django.db.models import F
# 需要先导入F
Book.objects.filter(commnetNum__lt=F('keepNum'))
# book表中,commentNum<keepNum的数据

Django 支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作

# 查询评论数大于收藏数2倍的书籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)

修改操作也可以使用F函数,比如将每一本书的价格提高30元:

Book.objects.all().update(price=F("price")+30) 

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

from django.db.models import Q
Q(title__startswith='Py')

Q 对象可以使用&| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

等同于下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

你可以组合&| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将“AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")

一些例子

 # 查询评论数大于阅读数的书籍
 from django.db.models import F,Q
 ret=Book.objects.filter(commit_num__gt=F('reat_num'))
 print(ret)
 # 把所有书籍的价格加10
 Book.objects.all().update(price=F('price')+10)

 # ----Q函数,描述一个与,或,非的关系
 # 查询名字叫红楼梦或者价格大于100的书
 ret=Book.objects.filter(Q(name='红楼梦')|Q(price__gt=100))
 print(ret)
 # 查询名字叫红楼梦和价格大于100的书
 ret = Book.objects.filter(Q(name='红楼梦') & Q(price__gt=100))
 print(ret)
 # # 等同于
 ret2=Book.objects.filter(name='红楼梦',price__gt=100)
 print(ret2)
 # 也可以Q套Q
 # 查询名字叫红楼梦和价格大于100  或者 nid大于2
 ret=Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100))|Q(nid__gt=2))
 print(ret)
 # ----非
 ret=Book.objects.filter(~Q(name='红楼梦'))
 print(ret)
 # Q和键值对联合使用,但是键值对必须放在Q的后面(描述的是一个且的关系)
 # 查询名字不是红楼梦,并且价格大于100的书
 ret=Book.objects.filter(~Q(name='红楼梦'),price__gt=100)
 print(ret)

标签:__,多表,Django,filter,objects,单表,obj,查询,book
来源: https://www.cnblogs.com/telecasterfanclub/p/13232261.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有