DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • Django

    • 框架引入
    • 基本配置
    • 单表记录CURD
    • 路由和视图层
    • 模版层
    • ORM查询
    • ORM字段
    • Ajax+layer
    • 自定义分页器
    • cookie与session
    • 中间件和csrf
    • Auth认证模块
    • ORM复习
      • 单表CURD
        • 增加
        • 查询
        • 更新
        • 删除
      • 多表CURD
        • 新增
        • 查询 - 对象
        • 查询 - 联表
        • 更新、删除
        • 自己创建第三张表
    • 测试Demo
  • 第一次学drf

  • 第二次学drf

  • 温故知新

  • flask

  • 后端
  • Django
DC
2023-11-07
目录

ORM复习

# 单表CURD

单表的CURD 下面的基本操作得熟练掌握,信手拈来!!

class Role(models.Model):
    name = models.CharField(verbose_name="角色名字", max_length=32)
    
    def __str__(self):
        return self.name
1
2
3
4
5

# 增加

from app01 import models
- ψ(`∇´)ψ 方式一
  res = models.Role.objects.create(name="管理员")       # 只要是queryset对象,就可以通过`.`query查看内部的sql语句!! 
  等同于
  res = models.Role.objects.create(**{"name":"管理员"}) # ★★★ 因为create的参数就是**kwargs
  
  返回的都是Role类实例化的对象,即Role表中当前添加的这条记录.
  既然是一个对象,就可以res.name、res.id、res.pk取值
  
  print(res)  # "管理员"  若Role表中没有__str__,这里的结果为Role object (1)

- ψ(`∇´)ψ 方式二
  obj = models.Role(**{"name":"管理员"})
  等同于
  obj = models.Role(name="管理员")  # 创建一个对象到内存中
  obj.save()                       # 执行该行语句才会写入到数据库中
  
  """应该联想到
  class A:
      def __init__(self):
          self.id = id
          self.name = name
      def __str__(self):
          return self.name
  a = A(1,"alex")
  print(a.id)
  print(a.name)
  """
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 查询

基于双下划线的查询

filter 、all 、exclude 、values 、values_list 、first 、last 、get 、exists 、order_by 、Q
distinct 、reverse 、count

查询一般有三个渠道: filter、Q对象、原生sql语句`from django.db import connection`!!
链式查询,只要调用方法的返回结果是QuerySet对象,就可以继续调用objects组件中的任一方法!!

■ filter all 
   - 返回的都是类似于列表的QuerySet对象,该对象里面是一条条记录/表的一个个实例化对象.
     eg: <QuerySet [<Role: Role object>, <Role: Role object>]>
     <注意:QuerySet对象不能直接通过json.dumps进行序列化,但QuerySet对象是可迭代的对象,可进行for循环!>
     for i in qs:
         print(i.id,i.title)
   - all、filter 若没找到,依旧返回queryset对象,但里面没有记录
     空的QuerySet对象 <QuerySet []> 是可以作为if判断的的条件的
    
■ filter里可以基于上下划线查询  <filter里面的多个条件用 ","连接 表明是and的关系>
  id = 2                    id=2
  id__gt = 2                id > 2          # select * from table where id > 2;
  id__gte = 2               id >= 2
  id__lt = 2                id < 2
  id__in = [1,2,3]          id in [1,2,3]   # select * from table where id in (1,2,3); 
  id__range = [18,40]       18 <= id <=40   # select * from table where id between in 18 and 40;
  name__contains = "s"         名字中含有“s”的,区分大小写  # select * from table where name like '%s%';
  name__icontains = "S"        名字中含有“S”的,忽略大小写
  name__startswith = "t"       名字中以“t”开头的名字,     # select * from table where name like "t%";
  name__endswith ='t'          名字中以“t”结尾的名字,     # select * from table where name like "%t";
  name__isnull = True          name is null
  create_time__year = '09'     查询9月份的数据
  create_time__month = '2020'  查询2020年的数据
  create_time__day = '11'      查询11号的数据,这三个可以结合使用,比如查询2020年9月份的数据
  """
  create_time = models.DateField(auto_now=True, auto_now_add=True)
  create_time = models.DateField()  # -- 可以不传参,自己指定时间
  
  models.DateTimeField -- 年月日 时分秒
  models.DateField     -- 年月日
    auto_now :     若值为True,只要本条数据有修改,就会将该字段的值更新
    auto_now_add : 若值为True,会自动帮忙添加本条数据的入库时间,若后续想要更改,需要手动
    
  注意: 在sqlite数据库添加字段类型为DateField的数据时会转成时间戳,这可能是个bug,不是你的问题.
  """
  
  
■ exclude + filter
  ★★★ 查询id不等于9的数据
  res = models.Role.objects.exclude(id=9).filter(name__contains = "户")
  
■ filter + values -- 指定查询字段!结果是列表套字典.
  res = models.Role.objects.filter(id__gt=0).values("id","name")  
  得到的依旧是类似于列表QuerySet对象.但里面是一个个字典!! eg:<QuerySet [{'id':..,"name":..},{'id':..,"name":..}]
  for i in qs:
      print(i['id'],i['title'])
      
■ filter + values_list -- 指定查询字段!结果是列表套元祖.
  res = models.Role.objects.filter(id__gt=0).values_list("id","title")  
  得到的依旧是类似于列表QuerySet对象.但里面是一个个元祖!!eg:<QuerySet [(6,"alex"),(7,"egon")]
    
■ filter + first (^_^)
  res = models.Role.objects.filter(id__gt=0).first()  # qs对象中下标为0的那条记录
  得到的是一条记录/一个对象 若没有,返回的是None
  ★★★ 链式查询,举一反三, qs.values().first()、qs.values_list().first()分别得到一个字典、一个元祖.
  
■ filter + last
  res = models.Role.objects.filter(id__gt=0).last()   # qs对象中下标为-1的那条记录
  得到的是一条记录/一个对象 若没有,返回的是None
  ★★★ 链式查询,举一反三, qs.values().last()、qs.values_list().last()分别得到一个字典、一个元祖.
  
■ filter + get   (^_^)
  res = models.Role.objects.filter(id__gt=0).get()
  get和first的区别,若QuerySet对象为空,前者报错,后者返回None
  所以get不建议用,非要用,需要try..except捕捉异常!
  
■ filter + exists
  res = models.Role.objects.filter(id__gt=0).exists()
  返回True或者False  其实,若filter的没有查询到,返回的是<QuerySet []>,也可以作为if的判断条件. 使用exists代码意思更明确.
  
■ filter + order_by
  # asc 根据id正序
  res = models.Role.objects.filter(id__gt=0).order_by("id")  
  # name desc,id asc ★★★ 根据name倒序排,当name相同时根据id正序排
  res = models.Role.objects.filter(id__gt=0).order_by("-name","id")  
  上述得到的依旧是类似于列表QuerySet对象.
  
■ Q对象
from django.db.models import Q
方式1:
	models.XX.objects.filter( Q(id=10) )	
	models.XX.objects.filter( Q(id=10)&Q(age=19) )	# and
	models.XX.objects.filter( Q(id=10)|Q(age=19) )  # or
	models.XX.objects.filter( Q(id__gt=10)|Q(age__lte=19) )	
  models.XX.objects.filter( Q( Q(id__gt=10)|Q(age__lte=19) ) & Q(name=19) )	
方式2:
  # id=1 or age=10
	q1 = Q()
	q1.connector = 'OR'
	q1.children.append(('id', 1))
	q1.children.append(('age', 10))  

	# size>10 and name=root
	q2 = Q()
	q2.connector = 'ADN'
	q2.children.append(('size__gt', 10))
	q2.children.append(('name', 'root'))  

	# (id=1 or age=10) and (size>10 and name=root)
	con = Q()
	con.add(q1, 'AND')
  con.add(q2, 'AND') 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

还有几个方法

#  -- distinct 去重查询!
#     若需要去重的查询数据中带有主键,去重就没有意义啦!所以我们要指定字段去重! So,强调,去重的前提的是数据一摸一样!千万别加id!
res = models.User.objects.values('name').distinct()

# -- reverse 翻转
#    强调!reverse反转有个前提,必须先排序!!
res = models.User.objects.order_by('age').reverse()

# -- count 数量,统计当前数据的个数
#    当然可以结合filter先进行筛选,然后再统计数量!
res = models.User.objects.count()
1
2
3
4
5
6
7
8
9
10
11

# 更新

-- 返回的是受影响的行数 
models.Role.objects.filter(name="管理员").update(name="alex")  # 找到所有记录,将name字段值都更新为"alex" 
models.Role.objects.update(name='EGON') # 这样操作的话,表中的数据全改了!! 一定要注意!

-- 还有种方式
obj = models.Role.objects.filter(name="管理员")
obj.name = "alex"
obj.save()
1
2
3
4
5
6
7
8

# 删除

-- 返回的是受影响的行数 
models.Role.objects.all().delete()
models.Role.objects.filter(name="管理员").delete()

上述是硬删除,还可以通过更新实现软删除!
1
2
3
4
5

# 多表CURD

涉及到外键啦!! 情况变得复杂了起来.

根据需求分析已知条件,先看已知条件所在表,然后理清与之相关联表的关系.. 从这些表中有外键的表起手比较容易.

xx__xx__xx__字段 / 跨到某表__跨到某表__跨到某表__该表的字段 . xx都是在跨表, 写一个xx就代表跨到了某张表! 只有最后是字段!!!
xx是外键-跨到外键所关联表.
xx是表名小写-跨到表名小写的那张表.(当然跨到的表名小写的那张表与跨之前所在的那张表肯定是有关系的)

eg: A表外键字段跨到B表.B表外键字段跨到C表.C表字段

Book:Publish = n:1
Book:Author  = n:n
Author:AuthorDetail = 1:1
    
-- 我们规定一本书只能由一个出版社出版,不考虑联合出版的情况.
   一个出版社可以出版多本书,  一对多的外键字段通常写在多的那方.即Book书籍表中.
-- 一本书可以有多个作者,一个作者可以写多本书 暂且有两种方式
   1> 可以使用ManyToManyField创建虚拟字段 此处我们将外键字段写在Book书籍表中. 下面关于示例中先使用它!!
   2> 自己手动创建第三张表.
-- 每个作者都可以有自己的详情  一般将一对一的外键字段写在经常查询的那张表.即Author作者表中.

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    title = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)


class AuthorDetail(models.Model):
    author = models.OneToOneField(to='Author', on_delete=models.CASCADE)
    phone = models.CharField(max_length=32)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 新增

image-20231030215158474

import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    """
    Book:Publish = n:1   ForeignKey在Book表中,字段名publish
    Book:Author = n:n    ManyToManyField在Book表中,虚拟字段名authors
    Author:AuthorDetail = 1:1   OneToOneField在AuthorDetail表中,字段名author
    """
    from api import models

    """★单表添加数据"""
    models.Publish.objects.create(title="四川出版社")
    models.Publish.objects.create(title="重庆出版社")
    models.Publish.objects.create(title="上海出版社")
    models.Publish.objects.create(title="北京出版社")
    
    models.Author.objects.create(name="张三")
    models.Author.objects.create(name="李四")
    models.Author.objects.create(name="王五")
    models.Author.objects.create(name="李六")

    """★多对一外键添加数据 有三种方式
    特别注意: 
       若publish_id的值不存在,因为外键约束,报错 ; 若publish_obj为None,报错
       (即 表“Book”的某条记录 通过外键指定的 关联表“Publish”中的那条记录 必须先存在!!)
       - 下方示例给 重庆出版社 添加了三本书 -- 即Book表中的两条记录关联了Publish表中的同一条记录
    """
    models.Book.objects.create(title="ABC1", price=100, publish_id=1)
    publish_obj = models.Publish.objects.filter(title="重庆出版社").first()
    models.Book.objects.create(title="ABC2", price=200, publish=publish_obj)
    models.Book.objects.create(title="ABC3", price=300, publish_id=publish_obj.pk)

    """★一对一外键添加数据 有三种方式.与上面一对多外键的三种方式并无两样"""
    models.AuthorDetail.objects.create(phone="12345", author_id=1)
    author_obj = models.Author.objects.filter(name="李四").first()
    models.AuthorDetail.objects.create(phone="23456", author=author_obj)
    author_obj = models.Author.objects.filter(name="王五").first()
    models.AuthorDetail.objects.create(phone="34567", author_id=author_obj.pk)

    """★多对多外键添加数据 往自动创建的第三张表中添加数据
    特别注意: 
       1> 在进行add操作时,Author表中得有这些id值的数据,若无,报错
       2> 在进行add操作是,若重复添加,无需担心,因为重复添加会自动删除.. 
          这也会造成自动创建的第三张表中的id是不连续的.
    理解: 
        拿到Book表中的一个对象/一条记录,先通过book_obj.authors跨到自动创建的第三张表
        再通过add操作在第三张表中添加 
            该条Book表的记录的pk 所对应的 多条Author表中记录的pk (1:n 一本书可以有多个作者) 
        Ps:当添加的第二本书的作者跟第一本书的作者有一样的,则构造出了一个作者可以写多本书
    思考: 
        多对多的关系本质就是两个1对多,若我分别在Book表和Author表中创建外键字段,两表彼此关联
        那么问题来了,我在添加数据的时候,因为外键字段的缘故,哪张表的数据要先存在呢?相互矛盾了,因此需要第三张表!
    """
    book_obj = models.Book.objects.filter(title="ABC1").first()
    book_obj.authors.add(1)
    book_obj.authors.add(1, 2, 3, 4)
    book_obj = models.Book.objects.filter(title="ABC2").first()
    book_obj.authors.add(2, 3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

# 查询 - 对象

image-20231030215207303

import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    """
    Book:Publish = n:1          ForeignKey在Book表中,字段名publish
    Book:Author = n:n           ManyToManyField在Book表中,虚拟字段名authors
    Author:AuthorDetail = 1:1   OneToOneField在AuthorDetail表中,字段名author
    
    需求:
    1> 正 n:1  查询“ABC1”这本书出自哪个出版社      
    2> 正 1:1  查询拥有电话号码“12345”的是哪位作者  
    3> 正 n:n  查询“ABC1”这本书的作者             
    4> 反 1:n  查询“重庆出版社“出版了哪些书         
    5> 反 1:1  查询“张三”作者的电话号码            
    6> 反 n:n  查询“李四”作者写了哪些书            
    """
    from api import models

    """ ★★★ 正向
    先否管是啥关系,拿到一个对象/一条记录,若该对象所在表有外键.
    通过 “对象.外键“ 跨到外键所关联的那张表.
    n:n的关系     另一方是是n -- 需“对象.外键.all()“,可得到外键关联的那张表中的多条记录
    n:1 1:1的关系 另一方是1。 -- “对象.外键“得到外键关联的那张表中的一条记录
    """

    """★多对一的外键查询 正向"""
    book_obj = models.Book.objects.filter(title="ABC1").first()
    print(book_obj.publish)  # Publish object (1)
    print(book_obj.publish.title)  # 四川出版社

    """★一对一的外键查询 正向"""
    authorDetail_obj = models.AuthorDetail.objects.filter(phone="12345").first()
    print(authorDetail_obj.author)  # Author object (1)
    print(authorDetail_obj.author.name)  # 张三

    """★多对多的外键查询 正向
    需求: 查询"ABC1"这本书所关联的作者对象!
    """
    book_obj = models.Book.objects.filter(title="ABC1").first()
    print(book_obj.authors)  # api.Author.None
    # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>,
    #            <Author: Author object (3)>, <Author: Author object (4)>]>
    print(book_obj.authors.all())

    """ ★★★ 反向
    先否管是啥关系,拿到一个对象/一条记录,若该对象所在表是 其余某张表的外键所关联的表.
    1:n n:n的关系 另一方是是n -- 需“对象.关联表表名小写_set.all()“,可得到有外键的那张表中的多条记录
    1:1的关系     另一方是1。 -- “对象.关联表表名小写“得到有外键的那张表中的一条记录
    通过 “对象.外键“ 跨到外键所关联的那张表.
    """

    """★一对多的查询 反向"""
    publish_obj = models.Publish.objects.filter(title="重庆出版社").first()
    print(publish_obj.book_set)  # api.Book.None
    # <QuerySet [<Book: Book object (2)>, <Book: Book object (3)>]>
    print(publish_obj.book_set.all())

    """★一对一的查询 反向"""
    author_obj = models.Author.objects.filter(name="张三").first()
    print(author_obj.authordetail)  # AuthorDetail object (1)
    print(author_obj.authordetail.phone)  # 12345

    """★多对多的查询 反向"""
    author_obj = models.Author.objects.filter(name="李四").first()
    print(author_obj.book_set)  # api.Book.None
    # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>
    print(author_obj.book_set.all())

    """★★若很想 通过对象.对象所在表的外键.外键所关联表中的字段 进行跨表查询. 使用select_related进行优化!!"""

    qs = models.Book.objects.all()  # 它只是一个单表查询的sql
    for obj in qs:
        # 先查询Book拿到Book表所有记录,这是一次单表查询
        # 然后循环,通过对象.外键.外键字段又进行了三次对Publish表的查询,共3次单表查询
        print(obj.title, obj.publish.title)

    qs = models.Book.objects.all().select_related("publish")  # 它是一个联表查询的sql,将两张表关联了起来
    for obj in qs:
        # 此处的obj.publish.title就不会进行数据库查询啦.
        # 因为数据在select_related进行inner join时就封装到对象里了.
        print(obj.title, obj.publish.title)

    # ABC1 四川出版社
    # ABC2 重庆出版社
    # ABC3 重庆出版社
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

# 查询 - 联表

image-20231030215321465

import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    """
    Book:Publish = n:1          ForeignKey在Book表中,字段名publish
    Book:Author = n:n           ManyToManyField在Book表中,虚拟字段名authors
    Author:AuthorDetail = 1:1   OneToOneField在AuthorDetail表中,字段名author
    
    联表查询,需求
    1> 查询“张三”这名作者的id和手机号
    2> 查询主键为“1”的书的书名和出版社的名字
    3> 查询主键为“2”的书的书名和作者
    4> 查询主键为“2”的书的书名、作者、作者手机号 (此需求跨了三张表)
    """
    from api import models

    """★★★
    models.table.object.filter().values() 查询的是哪张表,该表暂且称作 [基表]
    - 若基表中有外键,并且filter、values、values_list中的字段涉及到该外键所关联表中的字段.则是 “正向”
      ==> 正向查询涉及到另一张表的某个字段, `外键__另一张表的字段`
    - 若基表中没有外键,但该基表是“其余某表”中的外键所关联的表,
      filter、values、values_list中的字段涉及到“其余某表”中的字段. 则是 “反向”
      ==> 反向查询涉及到另一张表的某个字段, `另一张表的表名小写__另一张表的字段`
    Ps:若 公式中 另一张表的字段 是外键,那么可以继续正向查询!! 连续跨多张表!
    """

    # 查询“张三”这名作者的id和手机号
    # <QuerySet [{'id': 1, 'authordetail__phone': '12345'}]>
    models.Author.objects.filter(name='张三').values("id", "authordetail__phone")
    """下方三行代码中,author_id、author、author__id 大同小异 “id还可以替换成pk” """
    # <QuerySet [{'author_id': 1, 'phone': '12345'}]>
    models.AuthorDetail.objects.filter(author__name="张三").values("author_id", "phone")
    # <QuerySet [{'author': 1, 'phone': '12345'}]>
    models.AuthorDetail.objects.filter(author__name="张三").values("author", "phone")
    # <QuerySet [{'author__id': 1, 'phone': '12345'}]>
    models.AuthorDetail.objects.filter(author__name="张三").values("author__id", "phone")

    # 查询主键为“1”的书的书名和出版社
    # <QuerySet [{'title': 'ABC1', 'publish__title': '四川出版社'}]>
    models.Book.objects.filter(pk=1).values("title", "publish__title")
    # < QuerySet[{'book__title': 'ABC1', 'title': '四川出版社'}] >
    models.Publish.objects.filter(book__pk=1).values("book__title", "title")

    # 查询主键为“2”的书的书名和作者
    # < QuerySet[{'title': 'ABC2', 'authors__name': '李四'}, {'title': 'ABC2', 'authors__name': '王五'}] >
    models.Book.objects.filter(pk=2).values("title", "authors__name")
    # < QuerySet[{'book__title': 'ABC2', 'name': '李四'}, {'book__title': 'ABC2', 'name': '王五'}] >
    models.Author.objects.filter(book__id=2).values("book__title", "name")

    # 查询主键为“2”的书的书名、作者、作者手机号
    # <QuerySet [{'title': 'ABC2', 'authors__name': '李四', 'authors__authordetail__phone': '23456'},
    #            {'title': 'ABC2', 'authors__name': '王五', 'authors__authordetail__phone': '34567'}]>
    models.Book.objects.filter(pk=2).values("title", "authors__name", "authors__authordetail__phone")
    # <QuerySet [{'book__title': 'ABC2', 'name': '李四', 'authordetail__phone': '23456'},
    #            {'book__title': 'ABC2', 'name': '王五', 'authordetail__phone': '34567'}]>
    qs = models.Author.objects.filter(book__id=2).values("book__title", "name", "authordetail__phone")
    print(qs)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 更新、删除

import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    """
    Book:Publish = n:1          ForeignKey在Book表中,字段名publish
    Book:Author = n:n           ManyToManyField在Book表中,虚拟字段名authors
    Author:AuthorDetail = 1:1   OneToOneField在AuthorDetail表中,字段名author

    联表操作只能进行查询,其它操作(添加、删除、修改)是不支持的. 添加、删除、修改只能改变当前表的数据!!!跨不了一点.
    比如 想通过Book表的外键字段修改Publish表,直接报错!!
    models.Book.objects.filter(id=6).update(publish__title="上海出版社")
    """
    from api import models

    """n:1的更新、删除"""
    # -- ■ 修改 update
    # -- 方式一(推荐)
    models.Book.objects.filter(pk=1).update(title='水浒传1', publish_id=2)
    # -- 方式二
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(title='水浒传2', publish=publish_obj)

    # -- ■ 删除 delete
    #    默认是级联删除的!也就是该出版社对应的book数据也会在Book表中删除!!
    models.Publish.objects.filter(pk=1).delete()

    """n:n的更新、删除、清空"""
    # -- 修改 set
    #    同理,set里的可迭代对象的元素可以放对象,但不推荐!
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([2])  # -- 用元祖也可以,就一点,set的参数必须是可迭代对象!
    #    Django会先比对id为1的book,有没有对应的id为2、3的author
    #    若有,不动,没有就添加 -- 有查找比对的过程
    #    -- 这种方式不一定有先删除id为1的book对应的所有author,然后再添加的效率高
    book_obj.authors.set([2, 3])

    # -- 删除 remove
    book_obj = models.Book.objects.filter(pk=1).first()
    # -- 在第三张表中,将id为1的书对应的id为2的作者的这条记录删除..
    book_obj.authors.remove(2)
    # -- 也可以删除多个 若没有对应id为2的作者的记录删除,不会管,不碍事,不会报错
    book_obj.authors.remove(2, 3)

    # -- 清空 clear
    #    在第三张表中清空某个书籍与作者的绑定关系!相当于这本书没有作者.
    book_obj = models.Book.objects.filter(pk=2).first()
    res = book_obj.authors.clear()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 自己创建第三张表

通常情况下, 我们会手动创建第三张表, 通过第三张表正向进行查询, 这样比较清晰些!!

from django.db import models

class Boy(models.Model):
    name = models.CharField(max_length=32)

class Girl(models.Model):
    name = models.CharField(max_length=32)

class B2G(models.Model):
    bid = models.ForeignKey(to="Boy", on_delete=models.CASCADE)
    gid = models.ForeignKey(to="Girl", on_delete=models.CASCADE)
    addr = models.CharField(max_length=200)
    
    
import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    from api import models
    # -- 添加Boy表数据
    models.Boy.objects.create(name='张三')
    models.Boy.objects.create(name='李四')
    models.Boy.objects.create(name='王五')

    # -- 添加Girl表数据
    models.Girl.objects.bulk_create(
        objs=[models.Girl(name="小红"), models.Girl(name="小紫"), models.Girl(name="小粉")],
        batch_size=2,  # 共需查询数据库的次数: len(objs) / batch_size
    )

    # -- 添加B2G表的数据
    models.B2G.objects.create(bid_id=1, gid_id=1, addr="北京")
    models.B2G.objects.create(bid_id=1, gid_id=2, addr="上海")
    models.B2G.objects.create(bid_id=2, gid_id=2, addr="广州")
    b_obj = models.Boy.objects.filter(name="李四").first()
    g_obj = models.Girl.objects.filter(name="小粉").first()
    models.B2G.objects.create(bid=b_obj, gid=g_obj, addr="深圳")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

image-20231030222120523

import os

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'orm.settings')
    import django

    django.setup()

    """
    需求:
    1> 查询所有人的约会记录
    2> 查询李四的所有约会记录
    """

    from api import models

    # 1> 查询所有人的约会记录
    # <QuerySet [<B2G: B2G object (1)>, <B2G: B2G object (2)>, <B2G: B2G object (3)>, <B2G: B2G object (4)>]>
    qs = models.B2G.objects.all().select_related('bid', 'gid')
    for item in qs:
        # 注:因为使用了select_related 所以这里的item.bid.name等就不会做格外的跨表的查询操作.
        print(item.id, item.bid.name, item.gid.name, item.addr)
        """
        1 张三 小红 北京
        2 张三 小紫 上海
        3 李四 小紫 广州
        4 李四 小粉 深圳
        """

    # 2> 查询李四的所有约会记录  下述三种方式很明显第一种最复杂.
    # "b2g__gid__name"先是反向然后又是正向
    qs = models.Boy.objects.filter(name='李四').values("b2g__id", "name", "b2g__gid__name", "b2g__addr")
    # <QuerySet [
    #     {'b2g__id': 3, 'name': '李四', 'b2g__gid__name': '小紫', 'b2g__addr': '广州'}, 
    #     {'b2g__id': 4, 'name': '李四', 'b2g__gid__name': '小粉', 'b2g__addr': '深圳'}]>
    print(qs)

    qs = models.B2G.objects.filter(bid__name="李四").values("id", "bid__name", "gid__name", "addr")
    # <QuerySet [
    #     {'id': 3, 'bid__name': '李四', 'gid__name': '小紫', 'addr': '广州'},
    #     {'id': 4, 'bid__name': '李四', 'gid__name': '小粉', 'addr': '深圳'}]>
    print(qs)

    qs = models.B2G.objects.filter(bid__name="李四").select_related('gid')
    for item in qs:
        print(item.id, item.bid.name, item.gid.name)
        """
        3 李四 小紫
        4 李四 小粉
        """

    # 3> 若想通过Girl表来查李四的所有约会记录呢?? 反向正向都会涉及,不清晰
    # b2g反向到了第三张表B2G,b2g__bid拿到了第三张表的bid字段,该字段是外键,b2g__bid__name正向查询到了Boy表的name字段..
    qs = models.Girl.objects.filter(b2g__bid__name="李四"). \
        values("b2g__id", "b2g__bid__name", "b2g__gid__name", "b2g__addr")
    # <QuerySet [
    #     {'b2g__id': 3, 'b2g__bid__name': '李四', 'b2g__gid__name': '小紫', 'b2g__addr': '广州'},
    #     {'b2g__id': 4, 'b2g__bid__name': '李四', 'b2g__gid__name': '小粉', 'b2g__addr': '深圳'}]>
    print(qs)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

补充一点:

image-20231212214232581

你看实验的截图, 更新的时候,只要有数据库对应的字段在即可.. 离谱,我才意识到.


Auth认证模块
测试Demo

← Auth认证模块 测试Demo→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式