- 一对多 图书和出版社,外键建在查询次数多的一方
- 一对一 作者与作者详情 外键建在查询次数多的一方
- 多对多 图书与作者 需要创建第三张表专门存储关系
from django.db import models
# Create your models here.
‘‘‘
创建表关系
图书与出版社:一对多的关系
图书与作者:多对多的关系
作者与作者详情:一对一的关系
‘‘‘
# 创建图书表
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
# 总共8位有效数字,小数点占两位
‘‘‘
创建图书与出版社的关系 --- 一对多,外键建在查询次数多的哪一方
ForeignKey默认就是与出版社表的主键字段做外键关联
如果字段对应的是ForeignKey,那么orm会自动在字段的后面加上_id,如果在外键字段手动加了_id,那么orm还是会在后面继续加_id
‘‘‘
publish = models.ForeignKey(to=‘Publish‘)
‘‘‘
创建图书与作者的关系 ---- 多对多,外键建在查询频率较高的一方
author是一个虚拟字段,主要是用来告诉orm书籍表与作者表是多对多的关系,让orm自动创建第三张关系表
‘‘‘
author = models.ManyToManyField(to=‘Author‘)
# 创建出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# 创建作者表
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField
‘‘‘
作者表与作者详情表是一对一的关系,外键建在查询频率较高的一方
OneToOneField也会自动给字段加上_id后缀
‘‘‘
author_details = models.OneToOneField(to=‘AuthorDetails‘)
# 创建作者详情表
class AuthorDetails(models.Model):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
- orm中如何定义三种关系
- 一对多 外键字段 = models.FroeignKey(to=‘关联的表所对应的类名‘)
- 多对多 虚拟字段 = models.ManyToManyField(to=‘关联的表所对应的类名‘)
- 一对一 外键字段 = models.OneToOneField(to=‘关联的表所对应的类名‘)
- 外键字段是否会自动添加_id后缀
一对一 一对多都会在外键字段自动加_id后缀
多对多创建的第三张表也会自动加_id字段,第三张表就是两张不同表的主键字段的对应关系
- 其他知识
在django1.X版本中外键默认都是级联更新删除的
多对多的表关系可以有好几种创建方式 这里暂且先介绍一种
django自带的sqlite3数据库对日期格式不是很敏感,处理时容易出错
# 创建单表
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# 年月日
# register_time = models.DateField()
# 年月日时分秒
register_time = models.DateTimeField()
‘‘‘
auto_now:对表进行操作时就会将register_time的时间更新为当前时间
auto_now_add:创建数据的时间,后面不会再变
‘‘‘
验证orm的操作,即对数据的操作可以直接再测试环境中进行,无需使用前端页面与后端函数的对应关系来验证ORM对数据库的操作
app文件夹中的test.py是django提供的测试文件,也可以自己再app文件夹下创建测试的py文件。
测试环境搭建:
在test.py文件中写以下代码(直接复制manage.py中的前4行,自己写两行即可),
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "modles_layer.settings")
import django
django.setup()
测试环境使用:
使用测试环境进行测试的代码必须要在测试环境搭建完成后才能书写,案例如下
from django.test import TestCase
# Create your tests here.
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "modles_layer.settings")
import django
django.setup()
# 不要把这句代码写道文件开头,否则会报错,因为只有当测试环境搭建完成才能惊醒代码的测试
from app01 import models
print(models.User.objects.all())
‘‘‘
日期字段可以自己指定,但是一定要符合格式,用 - 链接,也支持日期对象
‘‘‘
user_dic = {‘name‘:‘鬼鬼‘,‘age‘:18,‘register_time‘:‘2020-01-01‘}
# 增加数据方式一
res = models.User.objects.create(**user_dic)
print(res.name) # 该方法有返回值,就是创建的数据对象本身
# 增加数据方式二
user_dic1 = {‘name‘:‘鬼鬼1‘,‘age‘:18,‘register_time‘:datetime.datetime.now()}
user_obj = models.User(**user_dic1)
user_obj.save()
‘‘‘
pk会自动查找当前表的主键字段指代的就是当前表的主键字段,用来pk之后不需要指代当前表的主键到底叫什么(id pid uid等等)
‘‘‘
# 方式一:批量删除
res = models.User.objects.filter(pk=6).delete()
print(res)
# 方式二:拿到单一对象,删除单一数据
user_obj = models.User.objects.filter(pk=8).first()
user_obj.delete()
# 修改数据
# 方式一:批量修改
models.User.objects.filter(pk=8).update(name=‘guigui‘)
# 方式二
user_obj = models.User.objects.get(pk=1)
‘‘‘
get方法返回的直接就是想要修改的数据对象,但是该方法不推荐使用,因为一旦数据不存在该方法就会直接报错,但是filter不会报错
‘‘‘
user_obj.name = ‘hah‘
queryset对象点query可以拿到返回值是queryset对象的orm语句所对应的sql语句
res = models.User.objects.values_list(‘name‘,‘age‘)
print(res) # <QuerySet [(‘鬼鬼‘, 18), (‘鬼鬼‘, 18), (‘鬼鬼‘, 18), (‘鬼鬼1‘, 18)]>
print(res.query) # 可以拿到对应的sql语句,该方法只能用于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‘,
},
}
可以指定获取数据的字段,类似于select name,age from ....
返回结果是queryset对象,列表套字典
res = models.User.objects.values(‘name‘,‘age‘)
print(res)
// <QuerySet [{‘name‘: ‘鬼鬼‘, ‘age‘: 18}, {‘name‘: ‘鬼鬼‘, ‘age‘: 18}, {‘name‘: ‘鬼鬼‘, ‘age‘: 18}, {‘name‘: ‘鬼鬼1‘, ‘age‘: 18}]>
可以获取指定字段的数据
返回结果是queryset对象,列表套元组
res = models.User.objects.values_list(‘name‘,‘age‘)
print(res)
# <QuerySet [(‘鬼鬼‘, 18), (‘鬼鬼‘, 18), (‘鬼鬼‘, 18), (‘鬼鬼1‘, 18)]>
# distinct去重,去重一定要是一摸一样的数据,如果带有主键去重,肯定无法进行去重
res = models.User.objects.values(‘name‘,‘age‘).distinct()
print(res)
res = models.User.objects.order_by(‘age‘)
# 默认是升序,降序就是在字段前加负号res = models.User.objects.order_by(‘-age‘)
print(res)
res = models.User.objects.order_by(‘name‘).reverse()
print(res)
res = models.User.objects.count()
print(res)
res = models.User.objects.exclude(name=‘鬼鬼‘)
print(res)
res = models.User.objects.filter(pk=2).exists()
print(res)
res = models.User.objects.filter(age__gt=30)
print(res)
res = models.User.objects.filter(age__lt=30)
print(res)
res = models.User.objects.filter(age__gte=32)
print(res)
res = models.User.objects.filter(age__lte=32)
print(res)
res = models.User.objects.filter(age__in=[18,21])
print(res)
res = models.User.objects.filter(age__range=[18,35])
print(res)
res = models.User.objects.filter(name__contains=‘n‘)
print(res)
res = models.User.objects.filter(name__contains=‘n‘)
print(res)
res = models.User.objects.filter(name__icontains=‘n‘)
print(res)
res = models.User.objects.filter(name__startswith=‘t‘)
res1 = models.User.objects.filter(name__endswith=‘n‘)
res = models.User.objects.filter(register_time__month=‘1‘)
print(res)
// month还可以换成year day 等,多个条件逗号链接表示and关系
from django.db import models
# Create your models here.
‘‘‘
创建表关系
图书与出版社:一对多的关系
图书与作者:多对多的关系
作者与作者详情:一对一的关系
‘‘‘
# 创建图书表
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
# 总共8位有效数字,小数点占两位
# publish_date = models.DateField(auto_now_add=True)
‘‘‘
创建图书与出版社的关系 --- 一对多,外键建在查询次数多的哪一方
ForeignKey默认就是与出版社表的主键字段做外键关联
如果字段对应的是ForeignKey,那么orm会自动在字段的后面加上_id,如果在外键字段手动加了_id,那么orm还是会在后面继续加_id
‘‘‘
publish = models.ForeignKey(to=‘Publish‘)
‘‘‘
创建图书与作者的关系 ---- 多对多,外键建在查询频率较高的一方
author是一个虚拟字段,主要是用来告诉orm书籍表与作者表是多对多的关系,让orm自动创建第三张关系表
‘‘‘
author = models.ManyToManyField(to=‘Author‘)
# 创建出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# email = models.EmailField() # varchar(254),后面校验型组件要用到
# 创建作者表
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField
‘‘‘
作者表与作者详情表是一对一的关系,外键建在查询频率较高的一方
OneToOneField也会自动给字段加上_id后缀
‘‘‘
author_details = models.OneToOneField(to=‘AuthorDetails‘)
# 创建作者详情表
class AuthorDetails(models.Model):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
models.Book.objects.create(name=‘西游记‘,price=400,publish_id=1)
models.Book.objects.create(name=‘明朝那些事‘,price=100,publish_id=2)
# 先获取外键关联的表中的数据(对象)
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(name=‘红楼梦‘,price=200,publish=publish_obj)
models.Publish.objects.filter(pk=1).delete()
# 删除出版社,那么和该出版社关联的书籍也会被删除
models.Book.objects.filter(pk=1).update(publish_id=2)
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
因为第三张关系表不是自己手动创建的。而是ORM自动帮你创建的,所以无法通过models.表名的方式拿到第三张表关系。拿到第三张表关系的方式请看下面的案例
# 首先拿到需要添加作者的书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
# 由于在定义书籍的表时,在类中定义了一个属性author,通过对象点属性的方式就可以拿到第三张关系表
print(book_obj.author)
# 为书籍添加作者
- 方式一:直接写作者的id
book_obj.author.add(2,3) # 书籍id为1的书籍绑定了id为2 3的作者,可以只添加一个作者括号内只写一个数字
- 方式二:写作者对象,可以自动解析出作者的id,然后关联给书籍
# 先获取作者对象,在将作者对象当作add的参数
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.author.add(author_obj,author_obj1,author_obj2)
# 首先拿到书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
# 删除书籍与作者的关系
- 方式一:直接写作者的id进行关系的删除
book_obj.author.remove(2) # 将当前书籍对象与id为2的作者接触关联,括号内可以写多个参数
- 方式二:写作者对象
author_obj = models.Author.objects.filter(pk=3).first()
book_obj.author.remove(author_obj)
# 首先拿到书籍对象
book_obj = models.Book.objects.filter(pk=1).first()
# 修改书籍与作者的对应关系
- 方式一:直接写作者的id进行关系的修改
book_obj.authors.set([1,2]) # 修改书籍与作者的对应关系,括号内必须是一个可迭代对象
- 方式二:写作者对象
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]) # 括号内必须给一个可迭代对
book_obj.authors.clear()
# 括号内没有任何参数
正向:外键字段在哪个表中,查关联的表就是正向
反向:被关联的表查外键字段所在的表就是反向
eg:通过书查出版社,就是正向---外键字段在书籍表中
通过出版社查书,就是反向---外键字段在书记表中
正向查询按字段(定义表的时候外键的名字)
反向查询按表名小写(-set)
在书写ORM语句的时候和写sql语句是一样的,不要企图一次性将ORM语句写完,如果比较复杂,就写一点看一点
正向什么时候需要加.all后缀呢?当查询的结果可能有多个的时候就需要加.all,如果是一个就直接拿到数据对象,(当你拿到的结果类似于这种app01.Author.None,说明ORM语句没有错误,只是查到的结果有多个,需要在ORM语句后面加上.all)
1.查询书籍主键为1的出版社
book_obj = models.Book.objects.filter(pk=1).first()
# 书查出版社--正向
res = book_obj.publish
print(res) # 得到的结果是出版社对象 Publish object
print(res.name)
print(res.addr)
2.查询书籍主键为1的作者
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.author
print(res) # <QuerySet [<Author: Author object>, <Author: Author object>]>
3.查询作者jason的电话号码
author_obj = models.Author.objects.filter(name=‘jason‘).first()
res = author_obj.author_details
print(res)
print(res.phone)
当查询结果可以有多个的时候及必须加_set
当查询结果只有一个的时候就不需要加_set
当查询的结果可能有多个的时候就需要加.all
1.查询出版社是东方出版社的书
publish_obj = models.Publish.objects.filter(name=‘东方‘).first()
res = publish_obj.book_set.all()
print(res)
2.查询作者是jason写的书
author_obj = models.Author.objects.filter(name‘jason).first()
res = author_obj.book_set.all()
print(res)
3.查询手机号是110的作者的姓名
author_detail_obj = models.AuthorDetails.objects.filter(phone=‘110‘).first()
res = author_detail_obj.author
print(res)
print(res.name)
1.查询jason的手机号和姓名
res = models.Author.object.filter(name=‘jason‘).values(‘author_details__phone‘,‘name‘)
# 通过外键字段直接mo跳到author_details表中,然后用`__`查找需要的字段值
2.查询书籍主键为1的出版社名称和书的名字
res = models.Book.object.filter(pk=1).values(‘name‘,‘publish__name‘)
# 首先拿到书籍对象,而书籍就是后面查询的基表,所以拿到书的名字直接写value(‘name‘)即可,而出版社的名字是通过外键字段跳到出版社的表中,然后通过`__`找到需要的字段值
3.查询书籍主键为1的作者姓名
res = models.Book.object.filter(pk=1).values(‘author__name‘)
1.查询jason的手机号和姓名,不能使用正向查询的方式,即不能使用models.Author...的方式
res = models.AuthorDetails.object.filter(author__name=‘jason‘).values(‘phone‘,‘author__name‘)
# 首先获取作者名是jason的作者的详细信息models.AuthorDetails.object.filter(author__name=‘jason‘)
# 然后,在详情表中获取电话
# 最后通过values跳转到作者表,通过__找到需要的字段值作者名
2.查询书籍主键为1的出版社名称和书的名字
res = models.Publish.object.filter(book__id=1).values(‘name‘,‘book_name‘)
3.查询书籍主键为1的作者姓名
res = models.Book.object.fliter(pk=1).values(‘name‘,‘author__name‘)
4.综合大案例 --- 查询书籍主键是1的作者的手机号
涉及到三张表:书籍表 作者表 作者详情表
res = models.Book.object.filter(pk=1).values(‘author__author_details__phone‘)
# 首先获取书籍对象,书籍关联了作者表,作者表又关联了作者详情表,
# 首先通过values和书籍表中作者的外键字段跳到作者表,然后再根据外键author_details调转到作者详情表通过__查询到所需的数据
原文:https://www.cnblogs.com/Kathrine/p/13027287.html