【django】关联模型类中数据的增删改查操作总结

导读:本篇文章讲解 【django】关联模型类中数据的增删改查操作总结,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

在这里插入图片描述


文章目录

一、多对一

正向操作

如果一个模型有外键字段,通过这个模型对外键的操作,叫做正向

1、改

给学生对象,赋值channel字段

方法一

s.channel_id=关联模型对象.id

In [29]: s=Student.objects.get(id=3)

In [32]: ch1=Channel.objects.get(id=4)

In [33]: s.channel_id=ch1.id

In [34]: s.save()

方法二

s.channel=关联模型对象

In [35]: s=Student.objects.get(id=4)

In [36]: ch1=Channel.objects.get(id=5)

In [37]: s.channel=ch1

In [38]: s.save()

2、删

把一个学生对象的channel字段删除,如果想要删除一个外键,定义模型类时定义外键字段需要有null=True的设置
s.channel=None 直接赋值外键为None
s.save()

In [40]: s=Student.objects.get(id=4)
In [41]: s.channel=None
In [42]: s.save()

或者
s.channel_id=None 直接赋值外键为None
s.save()

In [43]: s.channel_id=None
In [44]: s.save()

查看sql

In [45]: print(connection.queries[-1])
{'sql': "UPDATE `t_student` SET `name` = 'james', `age` = 18, `phone` = '13888888888', `address` = NULL, `create_tim
e` = '2023-01-06 07:07:17.669711', `channel_id` = NULL WHERE `t_student`.`id` = 4", 'time': '0.000'}

3、查

涉及跨表查询

反向操作

一个模型如果被另外一个模型的外键关联,那么通过这个模型对关联它的模型进行的操作叫反向

在这个模型的对象上,有一个反向字段,它的名字默认以关联模型名的小写加上_set构成,所以在Channel模型的对象上,有一个反向字段student_set,这个字段是一个关系型管理器,可以操作Student模型

In [48]: ch1.student_set
Out[48]: <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager at
0x1950e19ad90>

案例1:查询百度渠道下的所有学生信息

ch1.student_set.all():是查询集

In [46]: ch1=Channel.objects.get(id=5)

In [51]: ch1.student_set.all()
Out[51]: <QuerySet [<Student: james>, <Student: harden>]>

In [52]: print(connection.queries[-1])
{'sql': 'SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`,
 `t_student`.`create_time`, `t_student`.`channel_id` FROM `t_student` WHERE `t_student`.`channel_id` = 5 ORDER BY `t
_student`.`id` ASC LIMIT 21', 'time': '0.015'}

案例2:新增一个百度渠道下的学生

ch1.student_set.create(name='happy')

In [53]: ch1.student_set.create(name='happy')
Out[53]: <Student: happy>

In [54]: print(connection.queries[-1])
{'sql': "INSERT INTO `t_student` (`name`, `age`, `phone`, `address`, `create_time`, `channel_id`) VALUES ('happy', N
ULL, NULL, NULL, '2023-01-07 08:19:56.927533', 5) RETURNING `t_student`.`id`", 'time': '0.015'}

1、增

直接创建Student对象

直接通过关系型管理器创建学生对象

channel1=Channel.objects.get(id=2)
channel1.student_set.create(name=‘happy’)

2、改

方法一:add()

把多个学生对象添加进渠道的关联对象集中

案例1:将s1,s2,s3添加到百度渠道中

channel1.student_set.add(模型对象1,模型对象2,......)

In [55]: s1,s2,s3=Student.objects.all()[:3]

In [57]: channel1=Channel.objects.get(id=5)

In [58]: channel1.student_set.add(s1,s2,s3)

In [59]: print(connection.queries[-1])
{'sql': 'UPDATE `t_student` SET `channel_id` = 5 WHERE `t_student`.`id` IN (2, 3, 4)', 'time': '0.000'}

方法二:替换对象集

channel1.student_set.set([模型对象1,模型对象2,......])
这个set方法会先清空clear,后添加

案例2:将channel1模型对象下设置为学生s1和s2,之前不管channel1下面有多少学生都置为None

In [60]: channel1.student_set.set([s1,s2])

3、删

这里的删,是删关系,从channel对象的关联对象集中删除

a、从相关对象中清空指定的模型对象

案例1:清除某个渠道中的某些学生

ch1.student_set.remove(模型对象1,模型对象2,......)

In [64]: s1,s2,s3=Student.objects.all()[:3]

In [65]: channel1.student_set.remove(s1)

In [66]: print(connection.queries[-1])
{'sql': 'UPDATE `t_student` SET `channel_id` = NULL WHERE (`t_student`.`channel_id` = 5 AND `t_student`.`id` IN (2))
', 'time': '0.000'}

b、从相关对象中清空所有的模型对象

案例2:清除某个渠道中的所有的学生

channel1.student_set.clear()

In [67]: channel1.student_set.clear()

In [68]: print(connection.queries[-1])
{'sql': 'UPDATE `t_student` SET `channel_id` = NULL WHERE `t_student`.`channel_id` = 5', 'time': '0.000'}

4、查

关联管理器的查询和普通管理器没有区别

a、查所有

ch1.student_set.all():这里的查所有,有个前提条件,就是ch1的关联学生集合

b、查询来自抖音渠道的学生名叫kobe的学生

方法一

ch1.student_set.filter(name='kobe')

方法二

Student.objects.filter(channel__name='抖音',name='kobe')

In [75]: q1=Student.objects.filter(channel__name='抖音',name='kobe')

In [76]: q2=ch1.student_set.filter(name='kobe')

In [77]: print(q1.query)
SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`, `t_stude
nt`.`create_time`, `t_student`.`channel_id` FROM `t_student` INNER JOIN `t_channel` ON (`t_student`.`channel_id` = `
t_channel`.`id`) WHERE (`t_channel`.`name` = 抖音 AND `t_student`.`name` = kobe) ORDER BY `t_student`.`id` ASC

In [78]: print(q2.query)
SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`, `t_stude
nt`.`create_time`, `t_student`.`channel_id` FROM `t_student` WHERE (`t_student`.`channel_id` = 5 AND `t_student`.`na
me` = kobe) ORDER BY `t_student`.`id` ASC

c、自定义关联关系字段

在外键字段中使用related_name,可以自定义反向字段

channel = models.ForeignKey('Channel',
                                on_delete=models.RESTRICT,
                                null=True,
                                help_text='外键字段') , # 不允许删除,
                                related_name='students'

那么通过students进行操作

ch1.students.filter(name='kobe')

二、多对多

多对多两端都可以获得另一端的关系管理器,类似于多对一的反向关系

1、增

增一方面指的是创建关系对象

案例1:通过学生创建课程

s1.course_set.create(name='java')
course_set字段和多对一的反向字段一样

案例2:通过课程创建学生

c1.students.create(name='hao')
在当前业务场景下,这个业务不对

另一方面这里的改是建立关联关系,也就是在第三张表中插入数据

案例3:有学生s1,s2,s3,课程c1,c2,c3,学生s1报名了c1,c2

s1.course_set.add(c1,c2)

In [13]: c1=Course.objects.all()[0]

In [14]: c2=Course.objects.all()[1]

In [15]: c3=Course.objects.all()[2]

In [16]: s1,s2,s3=Student.objects.all()[:3]

In [17]: s1.student_set.add(c1,c2)

In [22]: print(connection.queries[-1])
{'sql': 'INSERT IGNORE INTO `t_course_students` (`course_id`, `student_id`) VALUES (1, 2), (2, 2)', 'time': '0.015'}

案例4:学生s2,s3报名了c2

c2.students.add(s2,s3)

In [23]: c2.students.add(s2,s3)

In [24]: print(connection.queries[-1])
{'sql': 'INSERT IGNORE INTO `t_course_students` (`course_id`, `student_id`) VALUES (1, 3), (1, 4)', 'time': '0.015'}

2、删

同多对一,也有remove和clear

案例5:学生s1,去掉课程c1的报名

s1.course_set.remove(c1)

In [25]: s1.course_set.remove(c1)

In [26]: print(connection.queries[-1])
{'sql': 'DELETE FROM `t_course_students` WHERE (`t_course_students`.`student_id` = 2 AND `t_course_students`.`course_id` I
N (2))', 'time': '0.000'}

案例6:课程c2,去掉学生s2的报名

In [27]: c2.students.remove(s2)

In [28]: print(connection.queries[-1])
{'sql': 'DELETE FROM `t_course_students` WHERE (`t_course_students`.`course_id` = 1 AND `t_course_students`.`student_id` I
N (3))', 'time': '0.000'}

案例7:清空clear

s.course_set.clear()

c.students.clear()

3、改

这里的改是建立关联关系

案例8:修改学生s1的报名为c1和c2,如果学生s2还有其他的报名,会被删掉

s1.course_set.set([c1,c2])

In [29]: s1.course_set.set([c1,c2])

In [30]: print(connection.queries[-1])
{'sql': 'INSERT IGNORE INTO `t_course_students` (`course_id`, `student_id`) VALUES (2, 2)', 'time': '0.000'}

案例9:修改课程c1的报名为s1和s2,如果还有其他的学生报名, 也会被删掉

c1.students.set([s1,s2])

4、查

一般多对多,主要用来查。

案例10:查报名了某个课程的学生

c1.students.all()

案例11:查某个学生报名的课程

s1.course_set.all()

多对多字段都是关系管理器,查询方法和默认管理器一致

可定义的反向字段名

同多对一

students = models.ManyToManyField('Student',
                                      help_text='报名学生',
                                      verbose_name='报名学生'),
                                      related_name='courses'

s1.courses.all()

三、一对一

一对一和多对一很像
一对一字段,指向的是关系模型的一个对象
在被关联的模型对象上,默认有一个字段,以关联模型名的小写作为名称。
所以student对象上,有一个字段studentdetail。这个字段指向StudentDetail的对象。
如果student对象还没有关联,调用这个字段会报错

在StudentDetail对象上有一个student字段,它指向Student对象

1、增

一般一对一字段的模型,在创建的时候,必须传递一对一关系的对象

案例1:给某个学生添加学生详情

StudentDetail.objects.create(student=s1,city='北京',salary=20000)

In [36]: StudentDetail.objects.create(student=s1,city='北京',salary=20000)
Out[36]: <StudentDetail: kobe>

In [37]: print(connection.queries[-1])
{'sql': "INSERT INTO `t_student_detail` (`student_id`, `city`, `company`, `station`, `salary`) VALUES (2, '北京', NULL, '
测试开发', '20000') RETURNING `t_student_detail`.`id`", 'time': '0.000'}

2、删

案例2:删除某个学生的学生详情

s1.studentdetail.delete()

3、改

案例3:修改某个学生的学生详情

s1.studentdetail.city='北京'
s1.save()

In [47]: StudentDetail.objects.create(student=s3,city='北京',salary=20000)
Out[47]: <StudentDetail: james>

In [48]: s3.studentdetail.city='长沙'

In [49]: s3.studentdetail.save()

案例4:修改某个学生详情对应学生的信息

sd.student.name='zs' sd.student.save()

4、查

不存在查

四、跨表查询

案例1:例如查询年龄大于18岁的学生都报名了那些课程?

Course.objects.filter(students__age__18)

In [51]: Course.objects.filter(students__age__gt=18)
Out[51]: <QuerySet [<Course: python开发>, <Course: 测试开发>]>

In [52]: print(connection.queries[-1])
{'sql': 'SELECT `t_course`.`id`, `t_course`.`name` FROM `t_course` INNER JOIN `t_course_students` ON (`t_course`.`id` = `t
_course_students`.`course_id`) INNER JOIN `t_student` ON (`t_course_students`.`student_id` = `t_student`.`id`) WHERE `t_st
udent`.`age` > 18 LIMIT 21', 'time': '0.000'}

Course.objects.filter(students__age__gt=18).distinct():过滤

In [54]: Course.objects.filter(students__age__gt=18).distinct()
Out[54]: <QuerySet [<Course: python开发>, <Course: 测试开发>]>

In [55]: print(connection.queries[-1])
{'sql': 'SELECT DISTINCT `t_course`.`id`, `t_course`.`name` FROM `t_course` INNER JOIN `t_course_students` ON (`t_course`.
`id` = `t_course_students`.`course_id`) INNER JOIN `t_student` ON (`t_course_students`.`student_id` = `t_student`.`id`) WH
ERE `t_student`.`age` > 18 LIMIT 21', 'time': '0.000'}

案例2:查询报名了python课程的学生?

Student.objects.filter(course__name__contains='python开发')

In [57]: Student.objects.filter(course__name__contains='python开发')
Out[57]: <QuerySet [<Student: kobe>]>

In [58]: print(connection.queries[-1])
{'sql': "SELECT `t_student`.`id`, `t_student`.`name`, `t_student`.`age`, `t_student`.`phone`, `t_student`.`address`, `t_st
udent`.`create_time`, `t_student`.`channel_id` FROM `t_student` INNER JOIN `t_course_students` ON (`t_student`.`id` = `t_c
ourse_students`.`student_id`) INNER JOIN `t_course` ON (`t_course_students`.`course_id` = `t_course`.`id`) WHERE `t_course
`.`name` LIKE BINARY '%python开发%' ORDER BY `t_student`.`id` ASC LIMIT 21", 'time': '0.000'}

案例3:查询百度渠道的学生,报名了那些课程

Course.objects.filter(students__channel__name='百度')

In [3]: Course.objects.filter(students__channel__name='抖音')
Out[3]: <QuerySet [<Course: python开发>, <Course: 测试开发>, <Course: 测试开发>]>

通过关系字段加双下划线进行跨表查询。

五、执行原生SQL

1、raw()方法

返回查询集,通过在管理器上调用raw方法来实现

q=Student.objects.raw('select id,name' from t_student where id=2)

In [6]: q=Student.objects.raw('select id,name  from t_student where id=2')

In [7]: q
Out[7]: <RawQuerySet: select id,name  from t_student where id=2>

打印sql

In [8]: print(q.query)
select id,name  from t_student where id=2

取值

In [9]: q[0]
Out[9]: <Student: kobe>

In [10]: q[0].name
Out[10]: 'kobe'

In [11]: q[0].age
Out[11]: 20

2、执行原生查询

执行调用原生数据驱动执行sql

with connection.cursor() as cursor:
    cursor.execute("select * from t_student")
    one=cursor.fetchone()
    print(one)
    two=cursor.fetchmany(2)
    print(two)
    all=cursor.fetchall()
    print(all)

执行结果

(2, 'kobe', 20, None, None, datetime.datetime(2023, 1, 1, 15, 26, 3, 84534), 5)
((3, 'li', 20, None, None, datetime.datetime(2023, 1, 1, 15, 26, 3, 84534), 1), (4, 'james', 18, '13888888888', None, datetime.datetime(2023, 1, 6, 7, 7, 17, 669711), 5))
((5, 'kelai', 22, '13688888888', None, datetime.datetime(2023, 1, 6, 7, 7, 17, 850752), 1), (6, 'kd', 19, '13888888777', None, datetime.datetime(2023, 1, 6, 7, 7, 17, 875757), 4), (7, 'harden', 18, '13888878228', None, datetime.datetime(2023, 1, 6, 7, 21, 25, 347180), 4), (8, 'curry', 22, '13688883388', None, datetime.datetime(2023, 1, 6, 7, 21, 25, 347180), 1), (9, 'ad', 19, '13888855577', None, datetime.datetime(2023, 1, 6, 7, 21, 25, 347180), 1), (10, 'happy', None, None, None, datetime.datetime(2023, 1, 7, 8, 19, 56, 927533), 4))

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/73917.html

(0)
小半的头像小半

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!