API配套数据库设计合理性咨询:附需求与Django实现代码
数据库模型设计检查:API开发需求对应实现是否遗漏?
需求回顾
- 城市区域(City district):包含name、id字段
- 分类(Category):包含name、id字段
- 组织网络(Organization Network):包含name、id字段
- 组织(Organization):
- 隶属于单个组织网络
- 包含id、name、description字段
- 可同时关联多个区域
- 拥有带价格的产品列表
- 产品(Product):
- 包含id、name、category字段
- 可在组织网络内的多个组织售卖
- 不同组织对应售价可能不同
你提供的Django模型代码
from django.db import models class District(models.Model): name = models.CharField(max_length=100, unique=True) class Category(models.Model): name = models.CharField(max_length=100, unique=True) class OrganizationNetwork(models.Model): name = models.CharField(max_length=100, unique=True) class Organization(models.Model): name = models.CharField(max_length=100, unique=True) description = models.TextField() organization_network = models.ForeignKey( OrganizationNetwork, on_delete=models.CASCADE, related_name="organizations", ) district = models.ManyToManyField( "District", through="DistrictOrganization", through_fields=("organization", "district"), related_name="organizations", ) products = models.ManyToManyField( "Product", through="OrganizationProduct", through_fields=("organization", "product"), related_name="organizations", ) class Product(models.Model): name = models.CharField(max_length=100, unique=True) category = models.ForeignKey( Category, on_delete=models.CASCADE, related_name="products" ) class DistrictOrganization(models.Model): district = models.ForeignKey(District, on_delete=models.CASCADE) organization = models.ForeignKey(Organization, on_delete=models.CASCADE) class OrganizationProduct(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2) organization = models.ForeignKey(Organization, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE)
设计遗漏与优化建议
1. 关联表的联合唯一约束缺失
目前DistrictOrganization和OrganizationProduct没有设置联合唯一约束,会出现以下问题:
- 同一个组织可能重复关联同一个区域
- 同一个产品在同一个组织下被添加多次(导致同一产品同一组织出现多份价格记录,不符合“不同组织对应售价可能不同”的需求逻辑,同一组织同一产品应该只有一个售价)
修复方案:给这两个模型添加联合唯一约束(Django 2.2+推荐使用UniqueConstraint):
# 修改DistrictOrganization class DistrictOrganization(models.Model): district = models.ForeignKey(District, on_delete=models.CASCADE) organization = models.ForeignKey(Organization, on_delete=models.CASCADE) class Meta: constraints = [ models.UniqueConstraint(fields=['district', 'organization'], name='unique_district_org') ] # 修改OrganizationProduct class OrganizationProduct(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2) organization = models.ForeignKey(Organization, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE) class Meta: constraints = [ models.UniqueConstraint(fields=['product', 'organization'], name='unique_product_org') ]
2. 产品与组织网络的关联限制缺失
需求明确产品“可在组织网络内的多个组织售卖”,但当前模型没有限制产品只能被同一组织网络内的组织售卖——也就是说现在的设计允许一个产品被不同组织网络的组织上架,这可能违背业务规则。
可选修复方案:
- 方案一:在
OrganizationProduct中添加organization_network字段,通过约束确保该字段与关联组织的organization_network一致:class OrganizationProduct(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2) organization = models.ForeignKey(Organization, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE) organization_network = models.ForeignKey(OrganizationNetwork, on_delete=models.CASCADE) class Meta: constraints = [ models.UniqueConstraint(fields=['product', 'organization'], name='unique_product_org'), models.CheckConstraint(check=models.Q(organization__organization_network=F('organization_network')), name='org_network_match') ] - 方案二:通过Django信号(如
pre_save)或业务逻辑层在保存OrganizationProduct时,验证组织的网络归属,不符合则抛出异常。
3. 字段可选性优化
Organization的description字段默认blank=False,如果业务允许组织没有描述信息,建议设置blank=True:
description = models.TextField(blank=True)
4. 命名规范优化(非功能遗漏,仅可读性提升)
Organization中的district字段名建议改为districts(因为是多对多关联,复数更直观),同时保持related_name="organizations"不变,这样反向查询district.organizations和正向查询organization.districts的语义更清晰。
内容的提问来源于stack exchange,提问作者karambaq
相关产品推荐
相关产品推荐

