Django表关系与表查询
1、一对多
首先来说说一对多,这个关联关系经常用到,多的一方通过models.ForeignKey进行关联。如下示例:
class Department(models.Model):
name = models.CharField(max_length=20)
create_data = models.DateField(auto_now_add=True)
is_delete = models.BooleanField(default=False) # default=False,在数据库中表现为0
class Meta:
# 这里定义了db_table的话,那么迁移后表名就是department这个了,不会是应用名_类名小写(例如:framework_department)
db_table = "department"
class Employee(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
gender = models.IntegerField(default=0)
# decimal_place = 2表示两位小数,max_digits表示8个数字,包括小数的两位
salary = models.DecimalField(max_digits=8,decimal_places=2)
# null=True 表示可以为空,blank=True表示django后台管理输入这个字段可以为空
comment = models.CharField(max_length=300,null=True,blank=True)
hire_data = models.DateField(auto_now_add=True)
department = models.ForeignKey("Department")
# department = models.ForeignKey("Department", related_name = 'employee') # 加了related_name = 'employee'后,在进行查询一个部门的全部员工时就不用employee_set了,直接使用employee即可。其余方法和使用employee_set一致。
class Meta:
db_table = "employee"
以上定义了两个模型,员工和部门是一对多关系,员工属于多的一方,所以使用了models.ForeignKey来与部门进行关联。关联的模型如果是定义在一个py文件里的话,那么可以直接写模型名称即可,例如:Department就可以直接使用,但是如果要关联不在一个py文件里的模型,那么就要通过:应用名.模型名使用(例如:user.User)。
以上都是关于模型的定义和使用,当然,最重要的是使用模型相关方法进行增删查改。
1.1、新增数据
新增Department:
Department.objects.create(name="生产部")
新增Employee:
Employee.objects.create(name="小明", age=18, gender=0, salary=8000.50, comment="新入职员工", department=1)
当然这样添加会报错:
ValueError: Cannot assign “1”: “Employee.department” must be a “Department” instance.
因为新增employee时,department需要传入一个实例对象,而不是单纯的一个ID。正确添加如下:
Employee.objects.create(name="小明", age=18, gender=0, salary=8000.50, comment="新入职员工", department=Department.objects.get(id=1))
Employee.objects.create(name="小张", age=18, gender=0, salary=9000.50, comment="新入职员工", department=Department.objects.filter(id=2)[0])
1.2、更新一个员工所属的部门:
Employee.objects.filter(id=1).update(department=3)
这里要注意的是,更新就不用传一个实例对象了,只需要传入部门id即可。传入实例对象会报错。
1.3、根据条件删除:
删除指定部门下的所有员工:
Employee.objects.filter(department=2).delete()
1.4、查询数据
一个员工所属的部门:
employee = Employee.objects.get(id=1)
employee_belong_department=employee.department
employee_belong_department_name= employee_belong_department.name
一个部门的全部员工:
department = Department.objects.get(id=1)
all_employee= department.employee_set.all()/a.employee_set.values()/a.employee_set.values_list()
使用外键时,一般都会定义一个删除的关联操作。什么意思呢?如下:
department = models.ForeignKey("Department", on_delete=models.CASCADE)
如果一个模型使用了外键。那么在对方那个模型被删掉后,该进行什么样的操作。可以通过on_delete来指定。可以指定的类型如下:
CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。如果我们强行删除,Django就会报错。
SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项, 前提是要指定这个字段一个默认值 。
SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去,可以不用指定默认值 。
DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。
2、多对多
class Student(models.Model):
name = models.CharField(max_length=16, verbose_name=u'名字')
age = models.IntegerField(verbose_name=u'年龄')
class Club(models.Model):
name = models.CharField(max_length=16)
members = models.ManyToManyField("Student")
2.1、新增数据
1、首先,多对多关系表在迁移时会生成三张表,虽然我们只定义了两张表,但是由于有ManyToManyField字段存在,会使得第三张表名字为:有ManyToManyField字段的模型名_字段名(例如:club_members)。这第三张表是自动生成的,当然,我们是可以控制这第三张表,稍后会说到
新增student:
Student.objects.create(name="小张", age=19)
Student.objects.create(name="小明", age=18)
Student.objects.create(name="小铭", age=19)
Student.objects.create(name="小林", age=17)
新增club:
Club.objects.create(name="跑步")
Club.objects.create(name="跳远")
Club.objects.create(name="跳高")
Club.objects.create(name="跳河")
club因为存在ManyToManyField字段,所以新增数据时,不能直接将该字段拿来使用
新增club_members:
先查询student数据
student = Student.objects.get(name="小林")
再查询club数据
club = Club.objects.get(name="跑步")
添加到关联表
club.members.add(student)
注意:add()这个方法接收的是一个对象,所以,如果要进行批量添加的话,如下:
students = Student.objects.all()
club = Club.objects.get(name="跑步")
club.members.add(*students)
2.2、查询数据
查询一个社团的全部成员
c = Club.objects.get(name="跑步")
c.members.all()/c.members.values()/c.members.values_list()
查询一个成员的全部社团
s = Student.objects.filter(id=1)
s.club_set.all()/s.club_set.values()/s.club_set.values_list() # 类名的小写+_set
2.3、更新数据
更新一个club下所有成员名字为1
b=Club.objects.get(name="ww")
b.members.update(name="1") # 返回更新条数,例如:3
2.4、删除数据
1、ManyToManyField是默认级联删除的,例如,如果要删除所有club下的某个student,那么就很简单了。
club=Club.objects.get(id=1) # 先查club
club.members.filter(name="ss").delete() # 再查student,name字段是关联的Student表的name
返回数据为:(6, {u’framework.Student’: 1, u’framework.Club_members’: 5}),表示Student表删除了一条数据,Club_members表删除了5条数据。如果没有该student,那么返回为(0, {})。从上面可以看出如果使用以上方法不仅会删除Student表中数据,还会删除Club表数据。
2、有时候我们不想删除那么多数据,例如只想删除某个club下的所有数据而不影响Student表中数据,那么可以使用如下方法:
club=Club.objects.get(id=1) # 先查要删除的那个club
club.members.clear() # 调用clear()方法删除所有关于该club的数据
3、有时候我们还想只删除某个club下的某个student数据,那么可以使用如下方法:
club=Club.objects.get(id=2) # 先查club
stu=Student.objects.get(id=2) # 再获取要删除的student
club.members.remove(stu) # 调用remove方法删除
3、自定义多对多表
前面说了多对多会自动创建一张关联表,这张表是可以自定义的。
class Student(models.Model):
name= models.CharField(max_length=16)
age = models.IntegerField()
class Club(models.Model):
name= models.CharField(max_length=16)
class Membership(models.Model):
student = models.ForeignKey("Student")
club = models.ForeignKey("Club")
这种多对多关联是自己定义的第三张关联关系表,所以操作起来会较前面简单。
3.1、新增数据
Membership.objects.create(student_id=1, club_id=1)
因为两个字段都是外键关联,所以操作时需要使用字段名_id的形式进行操作。
3.2、查询数据
查询一个学生所有的club
a=Student.objects.get(id=1)
b=a.membership_set.all()
查询一个club下的所有学生
a=Club.objects.get(id=1)
b=a.membership_set.all()
3.3、删除数据
Membership.objects.filter(student_id=1, club_id=1).delete()
返回值:(1, {u’framework.Membership’: 1})/(0, {u’framework.Membership’: 0})
好啦,文章到这里结束啦,谢谢浏览呀,祝各位看官老爷天天开心!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!