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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在这里插入图片描述


文章目录

一、多对一

正向操作

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

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报名了c1c2

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学生s2s3报名了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))

在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: go