You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django汽车清洗项目:模型关系设计与数据库分表咨询

Django汽车清洗项目模型设计与分表方案解答

问题1:SetOfServices的关联关系与套餐总价自动计算

关联关系选择

不能用ForeignKey,一个套餐包含多个SingleService,同时一个SingleService也可被多个套餐复用,属于**多对多(ManyToMany)**关联场景,应使用ManyToManyField定义关联。

套餐总价自动计算

两种常用实现方式:

  1. 保存时自动计算并存库:适合需频繁查询总价、后台直接展示的场景,通过重写模型save方法或Django信号实现。
  2. 动态计算(不存库):用@property装饰器实时计算,适合总价变化频繁、无需持久化的场景。

代码示例

from django.db import models

# 服务类型选项
SERVICES = (
    ('exterior', '外部清洗'),
    ('interior', '内饰清洁'),
    ('wax', '打蜡'),
    # 其他服务类型...
)

class SingleService(models.Model):
    name = models.CharField(max_length=100)
    service_type = models.CharField(max_length=20, choices=SERVICES)
    price = models.DecimalField(max_digits=8, decimal_places=2)

    def __str__(self):
        return self.name

class SetOfServices(models.Model):
    name = models.CharField(max_length=100)
    set_of_services = models.ManyToManyField(SingleService, related_name='service_sets')
    price_of_set = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)

    def save(self, *args, **kwargs):
        # 计算关联服务的总价
        total = self.set_of_services.aggregate(total=models.Sum('price'))['total'] or 0
        self.price_of_set = total
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name

复杂场景用信号实现:

from django.db.models.signals import m2m_changed
from django.dispatch import receiver

@receiver(m2m_changed, sender=SetOfServices.set_of_services.through)
def update_set_price(sender, instance, **kwargs):
    total = instance.set_of_services.aggregate(total=models.Sum('price'))['total'] or 0
    instance.price_of_set = total
    instance.save()

问题2:PostgreSQL中Django模型分表方案

通过db_table参数指定模型对应数据库表名即可实现分表,关联关系无需特殊修改,Django会自动识别目标模型的db_table并生成正确的SQL关联语句。

分表场景示例

按业务维度拆分Purchase模型为普通客户订单和VIP客户订单,或按时间维度拆分年度订单。

代码示例

  1. 定义抽象基类(避免重复代码):
from django.db import models

class BasePurchase(models.Model):
    customer = models.ForeignKey('Customer', on_delete=models.CASCADE)
    service_set = models.ForeignKey(SetOfServices, on_delete=models.CASCADE)
    payment_amount = models.DecimalField(max_digits=10, decimal_places=2)
    purchase_time = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True
  1. 分表模型实现:
class RegularPurchase(BasePurchase):
    class Meta:
        db_table = 'car_wash_regular_purchase'  # 指定PostgreSQL表名

class VIPPurchase(BasePurchase):
    discount_rate = models.DecimalField(max_digits=3, decimal_places=2, default=0.8)  # VIP专属字段

    class Meta:
        db_table = 'car_wash_vip_purchase'
  1. 按区域拆分客户模型:
class Customer(models.Model):
    name = models.CharField(max_length=100)
    car_info = models.CharField(max_length=200)
    # 其他字段...

    class Meta:
        abstract = True

class NorthCustomer(Customer):
    class Meta:
        db_table = 'car_wash_north_customer'

class SouthCustomer(Customer):
    class Meta:
        db_table = 'car_wash_south_customer'

关联关系注意事项

  • 外键直接指向分表后的模型即可,Django自动处理跨表关联。
  • 跨分表查询需手动指定目标模型,也可自定义管理器统一查询逻辑。
  • 迁移文件会自动为每个分表模型生成建表语句,执行迁移后PostgreSQL将创建独立表。

内容的提问来源于stack exchange,提问作者PrertoQuebas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 10:40:49