以下给出两张表格
class User(AbstractUser):
mobile=models.CharField(max_length=11,default=0,unique=True,verbose_name='手机号')
email_active=models.BooleanField(default=False,verbose_name='邮箱验证状态')
default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='默认地址')
class Meta:
db_table = 'tb_users'
verbose_name="用户"
verbose_name_plural=verbose_name
def __str__(self):
return self.username
from utils.models import BaseModel
class Address(BaseModel):
"""用户地址"""
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
title = models.CharField(max_length=20, verbose_name='地址名称')
receiver = models.CharField(max_length=20, verbose_name='收货人')
province=models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省')
city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
place = models.CharField(max_length=50, verbose_name='地址')
mobile = models.CharField(max_length=11, verbose_name='手机')
tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_address'
verbose_name = '用户地址'
verbose_name_plural = verbose_name
ordering = ['-update_time']
问题集:
主键和外键名字为什么不是一模一样
主键是用于唯一标识表中一条记录的字段,而外键是用来建立表与表之间关联的字段。外键的名称通常不会和主键完全相同,主要是为了避免混淆,并且在一个表中可能会有多个外键指向同一张表。例如,在 Address 表中:
province、city、district 都是外键,指向 areas.Area 表。
它们分别表示 省、市、区,虽然都指向同一张表 areas.Area,但代表不同的地址层级,所以它们的名字必须不同,否则会引起歧义。
为什么province,city,district 是外键?
在 Address 表中,province、city 和 district 这三个字段都是指向 areas.Area 表的外键,它们的作用是让每个 Address 记录的省、市、区字段都与 Area 表中的相应区域关联起来。
假设 areas.Area 表的结构如下:
class Area(BaseModel): name = models.CharField(max_length=20, verbose_name="名称") parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父级地区")
这样:
province 关联的是 Area 表中的 省级 数据;
city 关联的是 Area 表中的 市级 数据;
district 关联的是 Area 表中的 区县级 数据。
related_name 的作用
related_name 主要用于 Django 进行 反向查询,即:通过 外键关系 反向访问关联的表。默认情况下,Django 通过 外键名_set 进行反向查询,例如 area.address_set.all(),但 related_name 可以自定义这个反向查询的名称,提高代码的可读性和直观性。
在 Address 表中:
province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省') city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市') district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
表示:
province_addresses:查询所有 该省 下的地址
city_addresses:查询所有 该市 下的地址
district_addresses:查询所有 该区 下的地址
举例
假设 areas.Area 表中有以下数据:
id | name | parent_id |
---|---|---|
1 | 江苏省 | NULL |
2 | 南京市 | 1 |
3 | 玄武区 | 2 |
在 Address 表中,有如下数据:
id | user_id | province | city | district | place |
---|---|---|---|---|---|
1 | 10 | 1 | 2 | 3 | XX路100号 |
如何使用 related_name 进行查询?
# 获取江苏省(id=1)下的所有地址 province = Area.objects.get(id=1) print(province.province_addresses.all()) # 输出:<QuerySet [<Address: XX路100号>]> # 获取南京市(id=2)下的所有地址 city = Area.objects.get(id=2) print(city.city_addresses.all()) # 输出:<QuerySet [<Address: XX路100号>]> # 获取玄武区(id=3)下的所有地址 district = Area.objects.get(id=3) print(district.district_addresses.all()) # 输出:<QuerySet [<Address: XX路100号>]>
如果不使用 related_name,查询方法会变成:
print(province.address_set.all()) # 默认反向查询,名字不直观
所以 related_name 的作用是让查询逻辑更加清晰和直观。
2.什么是正向查询和反向查询
1. 正向查询
正向查询是指通过 外键字段从子表(即引用外键的表)查询父表(即外键所指向的表)中的数据。
在 Django 中,正向查询是从 子模型 到 父模型 的查询。例如,从 Address 表查询某个地址的 province(省),即通过 Address 中的 province 外键字段,查找 Area 表中的 name 字段。
正向查询的例子:
假设我们有以下模型:
class Area(models.Model): name = models.CharField(max_length=100) class Address(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) province = models.ForeignKey(Area, on_delete=models.PROTECT) city = models.ForeignKey(Area, on_delete=models.PROTECT)
如果你想从 Address 查询 province 对应的 Area,你可以执行正向查询:
address = Address.objects.get(id=1) print(address.province.name) # 获取地址的省名
结果:
print(address.province.name) # 输出: 河北省
*2. 反向查询*
反向查询是指从 父表 查询到 子表 关联的数据。在 Django 中,当你在 父模型(即引用外键的表)上使用反向查询时,它会自动创建一个从父模型到子模型的查询方法。
例如,你可以通过 Area 查询所有与某个 province(省)相关的 Address 记录。这里,Area 是父表,而 Address 是子表。
在 Address 模型中,你定义了:
province = models.ForeignKey('Area', on_delete=models.PROTECT, related_name='province_addresses')
related_name='province_addresses' 是反向查询的名字,它允许你通过 Area 查询到所有与该 Area 关联的 Address 记录。
反向查询的例子:
从 Area 查询与之关联的所有 Address,例如查找所有与某个省(province_id)相关的地址:
province = Area.objects.get(id=130000) addresses_in_province = province.province_addresses.all()
结果:
for address in addresses_in_province: print(address.title, address.receiver)