django(ORM)
一 单表(增、删、改、查)
1 测试脚本
'''
只想测试django中的某一个py文件内容,那么可以不用书写前后端交互的形式
而是直接写一个测试脚本即可
''' # 脚本代码无论是写在应用下的tests.py,还是自己单独开设py文件都可以
# 测试环境的准备,去manage.py中拷贝前四行代码,然后自己写两行
import os if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64project.settings")
import django
django.setup()
from app01 import models # 必须写到django.setup()下面,不能置顶,不然要报错,环境未准备好
# 在这个代码块的下面就可以测试django里面的py文件了
2 单表操作(增、删、改)
# django自带的sqlite3数据库对日期格式不是很敏感,处理的时候容易出错
# 增
models.User.objects.create(name='lq', age=18, register_time='2000-1-1') import datetime ctime = datetime.datetime.now()
user_obj = models.User(name='zd', age='18', register_time=ctime)
user_obj.save() # 删
res=models.User.objects.filter(pk=2).delete()
print(res)
'''
pk会自动查找到当前表的主键字段,指代的就是当前表的主键字段
用了pk之后,就不需要指代当前表的主键字段到底叫什么
uid
pid
sid
'''
# 第二种删除方法
user_obj=models.User.objects.filter(pk=2).first()
user_obj.delete() # 修改 models.User.objects.filter(pk=3).update(name='xiaobao') # 如果不想用filter 可以用get
# user_obj = models.User.objects.get(pk=3)
# user_obj.name='xiaobao'
# user_obj.save()
'''
get方法返回的就是当前数据对象
但是该方法不推荐使用
一旦数据不存在该方法会直接报错
而filter不会
所以还是用filter
'''
3 查看内部sql语句的方式
# 方式一
res=models.User.objects.values_list('name','age')
print(res)
# print(res.query)
# queryset对象才能够.query查看内部的sql语句 # 方式二:所有的sql语句都能查看
# 去配置文件中配置一下即可
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
4 必知必会13条(单表查询)
# 必知必会13条
# 1.all() 查询所有数据
# 2.filter() 带有过滤器条件的查询
# 3.get() 直接拿数据对象,但是条件不存在,直接报错 # 4.first() 拿querset里面第一个元素
# res = models.User.objects.all().first()
# print(res) # 5.last()
# res = models.User.objects.all().last()
# print(res) # 6.values() 可以指定获取到数据字段 类似sql语句select name,age from...
# res = models.User.objects.values('name', 'age')
# print(res) # 返回结果是列表套字典<QuerySet [{'name': 'lq', 'age': 18}, {'name': 'xiaobao', 'age': 18}]>
# print(res.query) # SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user` # 7.values_list() 返回结果是列表套元组
res=models.User.objects.values_list('name','age')
print(res) # 返回结果是列表套元组
print(res.query) #SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user`
'''
查看内部封装的sql语句
上述查看sql语句的方式,只能用于queryset对象
只有queryset对象才能能够点击query查看内部的sql语句
''' # 8.distinct() 去重
res = models.User.objects.values('name', 'age').distinct()
print(res)
'''
去重一定要一模一样的数据
如果带有主键那么肯定不一样,你在往后的查询中一定不要忽略主键
''' # 9.order_by()
res = models.User.objects.order_by('age') # 默认升序
res1 = models.User.objects.order_by('-age') # 降序
print(res)
print(res1) # 10.reverse() 反转的前提是 数据已经排过序 order_by()
res = models.User.objects.order_by('age').reverse()
print(res) # 11.count() 统计当前数据的个数
res = models.User.objects.count()
print(res) # 4 有4条数据 # 12.exclude() 排除在外
res = models.User.objects.exclude(name='xiaobao')
print(res) # 13.exists() 基本用不到,因为数据本身就自带布尔值,返回的是布尔值
res = models.User.objects.filter(pk=4).exists()
print(res)
5 神器的双下划线(单表查询)
# 1.年龄大于15岁的数据
res = models.User.objects.filter(age__gt=15)
print(res)
# 2.年龄小于15岁的数据
# res1 = models.User.objects.filter(age__lt=15)
# print(res1) # 3.大于等于、小于等于
# res = models.User.objects.filter(age__gte=15)
# print(res)
# res1 = models.User.objects.filter(age__lte=15)
# print(res1) # 年龄四18 或者14 或者6
# res = models.User.objects.filter(age__in=[18, 14, 6])
# print(res) # 年龄在18到40岁之间的 首尾都要
# res = models.User.objects.filter(age__range=[18, 40])
# print(res) # 查询出名字里面含有字母l的数据 模糊查询 默认区分大小写
# res = models.User.objects.filter(name__contains='l')
# print(res)
# 忽略大小写
# res = models.User.objects.filter(name__icontains='l')
# print(res) # 类似的还有:startswith,istartswith, endswith, iendswith # 根据注册时间来查询
# date字段可以通过在其后加__year, __month, __day等来获取date的特点部分数据
res = models.User.objects.filter(register_time__month='2')
res = models.User.objects.filter(register_time__year='2009') # 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)
# 需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~
二 多表操作(增、删、改)
1 一对多外键增删改
# 一对多外键增删改查
# 1.增
# 1)直接写实际字段 id
# models.Book.objects.create(title='水浒传', price=99.6, publish_id=1)
# models.Book.objects.create(title='西游记', price=44.6, publish_id=2)
# models.Book.objects.create(title='论语', price=64.6, publish_id=1)
# 2) 虚拟字段,对象
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='红楼梦', price=88.888, publish=publish_obj) # 2.删
# models.Book.objects.filter(pk=9).delete() # 级联删除 # 3.修改
# models.Book.objects.filter(pk=1).update(price=50)
# models.Book.objects.filter(pk=8).update(publish_id=1)
2 多对多外键增删改
# 多对多 增删改查 就是在操作第三张表
# 第三张表是ORM自动创建的,models.py中找不第三张表的类,所以通过书的对象来找第三张表,book_obj.author 就是对应的第三张表 # 如何给书籍添加作者
# book_obj=models.Book.objects.filter(pk=1).first()
# book_obj.authors.add(1) # 书籍id为1的书籍绑定一个主键为1的作者
# book_obj.authors.add(2,3) # book_obj=models.Book.objects.filter(pk=2).first()
# book_obj.authors.add(1)
# book_obj.authors.add(2,3)
# .add(),不但可以放主键值,还可以放对应的书籍或作者对象,虚拟字段
'''
add给第三张表关系表添加数据
括号内既可以传数字也可以传对象,并且都支持多个
''' # 删(也可以传对象)
# book_obj = models.Book.objects.filter(pk=1).first() # id=1的书籍
# book_obj.authors.remove(2) # book_obj = models.Book.objects.filter(pk=2).first() # id=2的书籍
# book_obj.authors.remove(1,3)
'''
remove
括号内既可以传数字也可以传对象,并且支持多个
''' # 修改 set
# book_obj = models.Book.objects.filter(pk=1).first() # id=2的书籍
# book_obj.authors.set([1,2]) # 括号内必须给一个可迭代对象,先删除,在修改
# book_obj.authors.set([3]) # author_obj = models.Author.objects.filter(pk=2).first()
# author_obj1 = models.Author.objects.filter(pk=3).first()
# book_obj.authors.set([author_obj, author_obj1])
'''
set
括号内必须传一个可迭代对象,对象内既可以传数字也可以传对象,并且都支持多个
先删除,后新增
''' # 清空
# 在第三张关系表中清空某个书籍与作者的绑定关系
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.clear()
'''
clear
括号内不要加任何参数
'''
三 多表查询
1 正方向的概念
# 正向
# 反向
外键字段在我手上,我查你就是正向
外键字段不在我手上,我查你就是反向 book>>>>publish 正向(外键字段在book)
publish>>>>book 反向 一对一和多对多正反向的判断也是如此 '''
正向查询按字段
反向查询按表名小写
_set
...
'''
2 子查询(基于对象的跨表查询)
# 基于对象的跨表查询(子查询,就是分步查询)
# 1.查询书籍主键为1的出版社
# book_obj = models.Book.objects.filter(pk=1).first()
# res = book_obj.publish # 正向查询,按字段,书查出版社,只有一个结果,不需要加.all()
# print(res)
# print(res.name)
# print(res.addr) # res是object对象 # 2.查询书籍主键为1的作者
# book_obj = models.Book.objects.filter(pk=1).first()
# 书查作者,正向,按字段查询
# res = book_obj.authors
# res1 = book_obj.authors.all() # 多对多关系,查询结果有多个,需要.all()
# print(res)
# print(res1) # res1的类型是queryset对象 # 3.查询作者lq的电话号码
# author_obj = models.Author.objects.filter(name='lq').first()
# res = author_obj.author_detail # 正向查询,按字段,只有一个结果,不用加.all()
# print(res.phone) # res的类型是object
'''
在书写orm语句的时候跟写sql语句一样
不要企图一次性将orm语句写完,如果比较复杂,就写一点看一点 总结:
正向什么时候需要加.all()
当你的结果可能有多个的时候就需要加.all()
如果是一个则直接拿到数据对象
book_obj.publish
book_obj.authors.all()
author_obj.author_detail
'''
# 4.查询出版社是中信出版的书(出版社查书,反向)
# publish_obj=models.Publish.objects.filter(name='中信出版社').first()
# res=publish_obj.book_set # app01.Book.None 有多个结果,需要加.all(),反向查询并有多个结果,小写表名_set.all()
# res1=publish_obj.book_set.all()
# print(res1) # 5.查询作者是cyz写过的书(作者查书,反向)
# author_obj = models.Author.objects.filter(name='cyz').first()
# res = author_obj.book_set.all()
# print(res) # 6.手机号是130的作者姓名(作者详情查作者,反向)
author_detail_obj=models.AuthorDetail.objects.filter(phone=130).first()
# res=author_detail_obj.author # 一对一的关系,结果只有一个,不需要加_set.all(),只需要小写表名
# print(res)
# print(res.name)
'''
基于对象
反向查询的时候
当你的查询结果可以有多个的 就必须加_set.all()
当你的结果只有一个的时候,不需要加_set.all()
'''
3 联表查询(基于双下划线的跨表查询)
# 基于双下划线的跨表查询(一行代码)
# 1.查询作者姓名zd的手机号
# res = models.Author.objects.filter(name='zd').values('author_detail__phone')
# print(res) # 正向查询,按字段,需要跨表的数据,__相应的表的字段名
# 反向
# res=models.AuthorDetail.objects.filter(author__name='zd').values('phone','author__name')
# print(res) # 反向查询,filter中,小写表名,__字段名,去跨表的值,__字段名 # 2.查询书籍主键为1的出版社名称和书的名称
# res = models.Book.objects.filter(pk=1).values('title', 'publish__name')
# print(res)
# 反向
# res = models.Publish.objects.filter(book__pk=1).values('name', 'book__title')
# print(res) # 3.查询书籍主键为1的作者姓名
# res = models.Book.objects.filter(pk=1).values('authors__name')
# print(res)
# 反向
# res = models.Author.objects.filter(book__pk=1).values('name')
# print(res) # 4.查询书籍主键是1的作者的手机号(跨三张表),跨到第二张表,再__跨下一张表,再__字段,取值
res=models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
print(res) # 正向按字段名
# 反向
res1=models.AuthorDetail.objects.filter(author__book__pk=1).values('phone','author__name')
print(res1) # 反向按小写表名
'''
总结:
只要掌握了正反向的概念
以及双下划线
那么就可以无限制的跨表 authors --> authors__author_detail --> authors__author_detail__phone
'''
4 聚合查询
# 聚合函数 aggregate
'''
聚合查询通常情况下都是配合分组一起使用
eg:只要跟数据库相关的模块
基本上都在django.db.models里面
如果上述没有那么应该再django.db里面
''' from django.db.models import Max, Min, Sum, Count, Avg # 所有书的平均价格
# res = models.Book.objects.aggregate(Avg('price'))
# print(res)
# 上述方法一次性使用
res=models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('title'),Avg('price'))
print(res)
5 分组查询
# 分组查询 annotate '''
MySQL分组查询都有那些特点
分组之后默认只能获取到分组的依据,组内其他字段都无法直接获取
严格模式
ONLY_FULL_GROUP_BY
''' from django.db.models import Count, Avg, Max, Min, Sum # 1.统计每一本书的作者个数
# res=models.Book.objects.annotate() # models后面.什么 就是按什么分组
# res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('author_num')
# author_num是起的别名 按书进行分组,通过书查作者,正向查询,按字段查询,涉及到跨表,__pk.
# print(res) # 2.统计每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(price_num=Min('book__price')).values('name', 'price_num')
# print(res) # 按出版社分组,通过出版社查书,反向查询,按小写表名,涉及到跨表,book__price # 3.统计不止一个作者的图书
# 1)先按照图书分组,求没一本书对应的作者数
# 2)过滤出不止一个作者的图书
# res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
# print(res)
'''
只要orm语句得出的结果还是一个queryset对象
那么它可以继续无限制的点queryset对象封装的方法
''' # 4.查询每个作者出的书的总价格
res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum')
print(res) '''
如果想按照指定的字段分组该如何处理?
models.Book.objects.values('price').annotate()
以书里的字典price进行分组 如果出现分组查询报错的情况
需要修改数据库严格模式
'''
多表查询总结:
MySQL中的多表操作
子查询
联表操作
inner join
left join
right join
union
Django ORM中
基于对象的跨表查询
子查询
先拿到一个数据对象
对象点点
(基于对象的子查询)多个结果 , 字段名.all(), 一个结果不用加
(基于对象的子查询)多个结果, 表名_set.all(),一个结果不用加
正向查询按外键字段,反向查询按表名小写
基于双下划线的跨表查询
联表操作
利用双下划线的跨表查询,__一次,跨一次表,取跨的值 ,__字段名
同样遵从,正向查询按外键字段,反向查询按表名小写
正反向的概念
正向
外键字段就在我手上
反向
外键字段不在我手中
小口诀
正向查询按外键字段
反向查询按表名小写
6 F与Q查询
# F查询
'''
我们构造的过滤器都只是将字段值与某个我们自己设定的常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢? Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
能够帮助你直接获取到表中某个字段对应的数据
'''
from django.db.models import F
# 1.查询卖出数大于库存数的书籍
# res = models.Book.objects.filter(sale__gt=F('inventory')).values('title')
# print(res) # 2.将所有书籍的价格提升300元
# models.Book.objects.update(price=F('price')+500) # 3.将所有书的名称后面加上爆款两个字
'''
在操作字符串类型的数据的时候,F不能直接做到字符串的拼接
'''
from django.db.models.functions import Concat
from django.db.models import Value
# models.Book.objects.update(title=Concat(F('title'),Value('(爆款)')))
# models.Book.objects.update(title=F('title')+'(爆款)') # 所有的名称会全部变成空白
# Q查询
# 1.查询卖出数大于100或者价格小于600的书籍
# res=models.Book.objects.filter(sale__gt=100,price__lt=400)
'''filter括号内多个参数是and关系'''
from django.db.models import Q
# res=models.Book.objects.filter(Q(sale__gt=100),Q(price__lt=400)) # Q包裹逗号分割,还是and关系
# res = models.Book.objects.filter(Q(sale__gt=100)|Q(price__lt=400)).values('title') # | or关系
# print(res)
# res = models.Book.objects.filter(~Q(sale__gt=100) | Q(price__lt=400)).values('title') # ~ not关系
# print(res)
# Q的高阶用法,能够将查询条件的左边也变成字符串的形式(动态的指定查询条件)
q=Q()
q.connector='or'
q.children.append(('sale__gt',100))
q.children.append(('price__lt',400))
res=models.Book.objects.filter(q) # 默认还是and关系
print(res)
7 django中如何开启事务
'''
事务
ACID
原子性
不可分割的最小单位
一致性
跟原子性是相辅相成
隔离性
事务之间相互不干扰
持久性
事务一旦确认永久生效 事务的回滚
rollback
事务的确认
commit
'''
目前只需要掌握Django中如何简单的开启事务
from django.db import transaction
with transaction.atomic():
sql1
sql2
# 在with代码块内书写的所有orm操作都是属于同一个事务
print('执行其他操作')
8 orm中常见字段及参数
AutuField
主键字段 primary_key=True CharField 类似于MySQL中的varchar
verbose_name 字段的注释
max_length 长度 IntegerField
BigIntegerField DecimalField
max_dights=8
decimal_places=2 8位,小数点后两位 EmailFiled varchar(254) DateField date
DateTimeField datetime
auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只有创建数据的时候记录创建时间后续不会自动修改 BooleanField(Field) 布尔值类型
该字段传布尔值(False/True) 数据库里面存0/1 TextField(Field) - 文本类型
该字段可以用来存大段内容(文章、博客...) 没有字数限制
后面的bbs作业 文章字段用的就是TextField FileField(Field) - 字符类型
upload_to="/data"
该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
/data/a.txt
后面bbs作业也会涉及 # 更多字段,看博客 # django除了给你提供了很多字段类型之外,还支持自定义字段
class Myfield(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
# 改了父类方法,就需要调用父类的init方法
super().__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection):
'''
返回真正的数据类型及各种约束条件
:param connection:
:return:
'''
return 'char({})'.format(self.max_length) my_char_field = Myfield(max_length=16, null=True) # 外键字段及参数
unique=True
ForeignKey(unique=True) === OneToOneField()
# 你在用前面字段创建一对一,Orm会有一个提示信息,orm推荐你使用后者但是前者也能用 db_index
如果db_index=True 则代表着为此字段设置索引 to_field
设置要关联的表的字段,默认不写关联的就是另外一张的主键字段 on_delete
当删除关联表中的数据时,当前表与其关联的行为 '''
django2.x及以上版本,需要你自己指定外键字段的级联更新级联删除
'''
9 数据库查询优化
only与defer '''
orm语句的特点:
惰性查询
如果你仅仅只是书写了orm语句,在后面根本没有用到该语句所查询出来的参数,那么orm会自动识别,直接不执行
''' # res=models.Book.objects.all()
# print(res) # 要用数据,才会去数据库查 # 想要获取书籍表中所有数的名字
# res=models.Book.objects.values('title')
# for i in res:
# print(i.get('title')) # 实现获取到的是一个数据对象,然后点title就能够拿到书名,并且没有其他字段
# res=models.Book.objects.only('title')
# print(res) # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>
# for i in res:
# print(i.title) # 点击only括号内的字段,不会走数据库
# print(i.price) # 点击only括号内没有的字段,会重新走数据库查询 # res=models.Book.objects.all()
# for i in res:
# print(i.price) # 不需要重新走数据库 res = models.Book.objects.defer('title') # 对象除了没有title属性之外其他的都有
for i in res:
print(i.price)
'''
defer和only刚好相反
defer括号内放的字段不在查询出来的对象里面,查询该字段需要重新走数据
而如果查询的是非括号内的字段,则不需要走数据库
'''
10 select_related与prefetch_related 跨表操作有关
# res=models.Book.objects.all()
# for i in res:
# print(i.publish.name) # 每循环一次就要走一数据库查询 # res=models.Book.objects.select_related('publish') # INNER JOIN
'''
select_related 内部直接先将Book与publish连起来,然后一次性将大表里面的所有数据
全部封装给查询出来的对象
这个时候对象无论是否点击book表的数据还是publish的数据都是无需再走数据库查询 select_related括号内只能放外键字段 一对多 一对一
'''
# for i in res:
# print(i.publish.name) res=models.Book.objects.prefetch_related('publish') # 子查询
"""
prefetch_related 该方法内部其实就是子查询
将子查询出来的所有结果也给你封装到对象中
给你感觉好像也是一次性搞定
"""
for i in res:
print(i.publish.name)
四 补充字段
1 choices参数(数据库字段设计常见)
'''
用户表
性别
学历
工作经验
是否结婚
是否生子
客户来源 针对某个可以列举完全的可能性字段,我们应该如何存储
只要某个字段的可能性是可以列举完全的,那么一般情况下都会采用choice参数
''' class User(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
# 性别
gender_choices = (
(1, '男'),
(2, '女'),
(3, '其他'),
)
gender = models.IntegerField(choices=gender_choices) '''
该gender字段存的还是数字,但是如果存的数字在上面元组列举的范围之内
那么可以非常轻松的获取到数字对应的真正的内容 1.gender字段存的数字不在上述元组列举的范围内容
2.如果在,如何获取对应的信息
'''
score_choices = (
('A', '优秀'),
('B', '良好'),
('C', '及格'),
('D', '不及格'),
) score = models.CharField(choices=score_choices, null=True) # models.User.objects.create(username='lq', age=18, gender=1)
# models.User.objects.create(username='zd', age=30, gender=2)
# models.User.objects.create(username='cyz', age=6, gender=3)
# 存的时候,没有列举出来的数字也能存(范围还是按照字段类型决定)
# models.User.objects.create(username='cys', age=14, gender=4) # 取
user_obj = models.User.objects.filter(pk=1).first()
print(user_obj.gender)
# 只要有choices参数的字段,如果你想要获取对应的信息,固定写法 get_字段名_display()
print(user_obj.get_gender_display())
# 男 user_obj = models.User.objects.filter(pk=4).first()
print(user_obj.get_gender_display())
# 4
# 如果没有对应关系,那么字段是什么还是展示什么 # choices参数使用场景是非常广泛的
2 MTV与MVC模型
# MTV:Django号称是MTV模型
M:models
T:templates
V:views # MVC:其实Django本质也是MVC
M:models
V:views
C:controller(控制器) # vue框架:MVVM模型
3 多对多三种创建方式
# 全自动
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author') class Author(models.Model):
name = models.CharField(max_length=32)
'''
优点:非常的方便,还支持orm提供操作第三方关系表的方法
缺点:第三张表的扩展性极差(没有办法额外添加字段)
'''
# 纯手动
class Book(models.Model):
name = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32) class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author') '''
优点:第三张表完全取决于自己进行额外的扩展
缺点:需要写的代码较多,不能够再使用orm提供的简单方法add、remove
不建议使用该方式
'''
# 半自动
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author',
through='Book2Author',
through_fields=('book', 'author')
)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author') '''
through_fields字段先后顺序
判断的本质:
通过第三张表查询对应的表,需要用到那个字段就把那个字段放前面
也可以简化判断
当前表是谁,就把对应的关联字段放前面
半自动:可以使用orm的正反向查询,但是没法使用add,set,remove,clear这四个方法
''' # 总结:需要掌握全自动和半自动,为了扩展性更高,一般采用半自动
django(ORM)的更多相关文章
- Django进阶Model篇—数据库操作(ORM)
一.数据库配置 django 默认支持sqlite.mysql.oracle.postgresql数据库,像db2和sqlserver之类的数据库需要第三方的支持,具体详见https://docs.d ...
- 建立一个更高级别的查询 API:正确使用Django ORM 的方式(转)
add by zhj: 本文作者是DabApps公司的技术主管,作者认为在view中直接使用Django提供的ORM查询方法是不好的,我对此并不赞同,可能作者 写这篇文章是给Django的初学者看,所 ...
- python3开发进阶-Django框架的起飞加速一(ORM)
阅读目录 ORM介绍 Django中的ORM ORM中的Model ORM的操作 一.ORM介绍 1.ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一 ...
- 【python】-- Django ORM(进阶)
Django ORM(进阶) 上一篇博文简述了Django ORM的单表操作,在本篇博文中主要简述Django ORM的连表操作. 一.一对多:models.ForeignKey() 应用场景:当一张 ...
- 【python】-- Django ORM(基础)
Django ORM(基础) Django 框架十分强大,自带数据库操作功能.Django 跟 SQLAchemy 一样,也是通过ORM(Object Relational Mapping,关系对象映 ...
- Django orm进阶查询(聚合、分组、F查询、Q查询)、常见字段、查询优化及事务操作
Django orm进阶查询(聚合.分组.F查询.Q查询).常见字段.查询优化及事务操作 聚合查询 记住用到关键字aggregate然后还有几个常用的聚合函数就好了 from django.db.mo ...
- Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段
单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...
- django 模型层(orm)05
目录 配置测试脚本 django ORM基本操作 增删改查 Django 终端打印SQL语句 13条基本查询操作 双下滑线查询 表查询 建表 一对多字段数据的增删改查 多对多字段数据的增删改查 基于对 ...
- django ORM教程(转载)
Django中ORM介绍和字段及字段参数 Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简 ...
- Python之路【第二十一篇】Django ORM详解
ORM回顾 关系对象映射(Object Relational Mapping,简称ORM). django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 对于ORM框 ...
随机推荐
- delphi 异常测试(我自己捕捉)
由于最近的短信模块老是报SocketErorr错误,有的时候也不确定是哪里有问题,影响短信的销售,所以这里这样写,把出现的异常捕捉到显示出来.然后跳过这个不发送 ------------------- ...
- NC50439 tokitsukaze and Soldier
题目链接 题目 题目描述 在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本. 第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和. 但是这些士兵有特殊的要求 ...
- NC51222 Strategic game
题目链接 题目 题目描述 Bob enjoys playing computer games, especially strategic games, but sometimes he cannot ...
- NAND flash 扫盲博客
从SSD角度学习NAND Flash(一)_小小单片机的博客-CSDN博客 从SSD角度学习NAND Flash(二)_ssd和nand 的交互_小小单片机的博客-CSDN博客 从SSD角度学习NAN ...
- centos7创建MySQL自动备份脚本
说明 最近需要给wordpress站点搞一个定时备份mysql数据库,所以记录一下. 操作步骤 1.创建备份脚本 这一步最重要,创建目录:/home/wpblog_backup,然后在目录下创建she ...
- SpringBoot下Akka的简单使用
SpringBoot下Akka的简单使用 Akka框架实现一个异步消息传输,通过定义演员来处理业务逻辑. 首先引入依赖 <!-- akka --> <dependency> & ...
- python3 pip3 安装python-ldap失败
pip3安装时提示 ERROR: Could not build wheels for python-ldap, uWSGI, M2Crypto, which is required to insta ...
- C++ 使用 UTF8 BOM 替换 UTF8 文件
void Utf8ToUtf8Bom(const wchar_t* filename) { std::ifstream infile; std::string strline; std::string ...
- Ansible的基本配置
目录 定义主机和组 主机的定义 主机组的定于 主机组的嵌套 选择主机和组 匹配主机 使用通配符匹配 配置文件优先级 配置文件详解 配置文件段 配置文件参数说明 配置案例 1. 在节点上创建一个普通用户 ...
- Conda简单教程
目录 什么是Conda 安装Conda 虚拟环境管理 模块管理 何时使用Conda 什么是Conda Conda是Python中用于管理包和虚拟环境的一大利器. 使用Conda可以非常便利的使用数据科 ...