- ORM对关联表的操作
- 在models.py中定义两个Model,对应两张表
-
1 # common.models.py
2 # 国家表
3 class Country(models.Model):
4 name = models.CharField(max_length=100)
5
6 # 学生表, country 字段是国家表的外键,形成一对多的关系
7 class Student(models.Model):
8 name = models.CharField(max_length=100)
9 grade = models.PositiveSmallIntegerField()
10 country = models.ForeignKey(Country,
11 on_delete=models.PROTECT)
- 执行python manage.py makemigrations common
- 执行python manage.py migrate
- 执行python manage.py shell
- 输入代码
from common.models import *
c1 = Country.objects.create(name='中国')
c2 = Country.objects.create(name='美国')
c3 = Country.objects.create(name='法国')
Student.objects.create(name='白月', grade=1, country=c1)
Student.objects.create(name='黑羽', grade=2, country=c1)
Student.objects.create(name='大罗', grade=1, country=c1)
Student.objects.create(name='真佛', grade=2, country=c1)
Student.objects.create(name='Mike', grade=1, country=c2)
Student.objects.create(name='Gus', grade=1, country=c2)
Student.objects.create(name='White', grade=2, country=c2)
Student.objects.create(name='Napolen', grade=2, country=c3)
- 外键表字段访问(Student->Country)
- s1 = Student.objects.get(name = '白月'):获取到一个学生对象,怎么得到他的国家名称?
- s1.country.name:获取国家的名称
- 外键表字段过滤
- 获取Student表中所有一年级的学生:Student.objects.filter(grade=1).values()
- 查找Student表中所有一年级中国学生:
- cn = Country.objects.get(name='中国') Student.objects.filter(grade=1,country_id=cn.id).values() √
- cn = Country.objects.get(name='中国') Student.objects.filter(grade=1,country=cn).values() √
- 上面的方法,写起来麻烦,有两步操作,需要发送两次数据请求给数据库服务器,性能不高
- 中间方案:Student.objects.filter(grade=1,country__name='中国').values('name','country__name')
- 选择出来的记录中,国家名是country__name,两个下划线比较怪
- 有时候前后端接口的设计者,定义好了接口格式,如果要求一定是countryname这个怎么办呢?
- 最终方案:
from django.db.models import F
# annotate 可以将表字段进行别名处理
Student.objects.annotate(
countryname=F('country__name'),
studentname=F('name')
).filter(grade=1,countryname='中国').values('studentname','countryname')
- 外键表反向访问
- 外键表字段访问时通过表外键字段表示,比如Student表的country字段
- 反向关系时通过表Model名转化成小写表示的
- 如果已经获取了一个Country对象,如何获取到所有属于这个国家的学生呢?:通过表Model名转化为小写,后面加上_set来获取所有的反向外键关联对象
- cn = Country.objects.get(name='中国')cn.student_set.all()
- django给出了一个方法,可以更直观的反应关联关系,在定义Model的时候,外键字段使用related_name参数
# 国家表
class Country(models.Model):
name = models.CharField(max_length=100)
# country 字段是国家表的外键,形成一对多的关系
class Student(models.Model):
name = models.CharField(max_length=100)
grade = models.PositiveSmallIntegerField()
country = models.ForeignKey(Country,
on_delete = models.PROTECT,
# 指定反向访问的名字
related_name='students')
-
- 可能会遇到AttributeError: 'Country' object has no attribute 'students':关闭django shell,重启启动即可。
- 反向过滤
- 如果我们要获取所有具有一年级学生的国家名?
- country_ids = Student.objects.filter(grade=1).values_list('country',flat=True) Country.objects.filter(id__in=country_ids).values()
- 使用distinct()消除重复:
-
# 先获取去重后的国家ID
country_ids = Student.objects.filter(grade=1).values_list('country', flat=True).distinct()
# 再查询
Country.objects.filter(id__in=country_ids).values()
- Country.objects.filter(students__grade=1).values()
- Country.objects.filter(students__grade=1).values().distinct()
- 据说.distinct()对MySQL数据库无效