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

Django 不支持复合主键时查询供应商对指定买家折扣的实现方案

实现方案

Django本身不支持复合主键,但不需要依赖复合主键也能实现你的业务需求,以下是两种可落地的方案:

方案1:保留现有表结构,通过联合唯一约束查询

你已经给Discount表设置了supplier_id和buyer_id的联合唯一约束,该约束已经能保证同一供应商对同一买家只会有一个有效折扣,完全可以替代复合主键的业务唯一性作用。

模型定义参考

from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()

class Discount(models.Model):
    supplier = models.ForeignKey(User, on_delete=models.CASCADE, related_name="supplied_discounts")
    buyer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="received_discounts")
    discount_rate = models.DecimalField(max_digits=5, decimal_places=2, help_text="示例值0.8代表8折")

    class Meta:
        # Django 3.2+ 推荐用UniqueConstraint替代unique_together,扩展性更强
        constraints = [
            models.UniqueConstraint(fields=['supplier', 'buyer'], name='unique_supplier_buyer_discount')
        ]

class Product(models.Model):
    product_name = models.CharField(max_length=128)
    supplier = models.ForeignKey(User, on_delete=models.CASCADE, related_name="supplied_products")
    buyer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="available_products")
    price = models.DecimalField(max_digits=10, decimal_places=2)

常见场景查询代码

  • 单个商品查询场景
# 假设当前登录用户为买家,查看id为12的商品详情
product = Product.objects.get(id=12)
try:
    discount = Discount.objects.get(supplier_id=product.supplier_id, buyer_id=request.user.id)
    discounted_price = product.price * discount.discount_rate
except Discount.DoesNotExist:
    # 无匹配折扣时默认返回原价
    discounted_price = product.price
  • 商品列表批量查询场景(避免N+1查询问题)
from django.db.models import Subquery, OuterRef, F, DecimalField

current_buyer_id = request.user.id
# 构造折扣子查询
discount_subquery = Discount.objects.filter(
    supplier_id=OuterRef('supplier_id'),
    buyer_id=current_buyer_id
).values('discount_rate')[:1]

# 批量查询当前买家可见的所有商品,并附带计算折扣价
products = Product.objects.filter(
    buyer_id=current_buyer_id
).annotate(
    discount_rate=Subquery(discount_subquery, output_field=DecimalField(max_digits=5, decimal_places=2))
).annotate(
    discounted_price=F('price') * F('discount_rate')
)

# 处理无折扣的商品
for product in products:
    if not product.discounted_price:
        product.discounted_price = product.price

方案2:抽取供应商-买家关联表(适合业务后续扩展)

如果后续还会新增供应商和买家的绑定属性(比如专属账期、配送规则、合同有效期等),可以单独抽取一张关联表,Discount和Product都关联该表的单主键,逻辑更清晰。

调整后模型定义参考

from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()

# 新增供应商-买家关联表
class SupplierBuyerRelation(models.Model):
    supplier = models.ForeignKey(User, on_delete=models.CASCADE, related_name="buyer_relations")
    buyer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="supplier_relations")
    # 可扩展其他公共属性:is_active、contract_no、delivery_cycle等

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['supplier', 'buyer'], name='unique_supplier_buyer_relation')
        ]

class Discount(models.Model):
    # 折扣和关联表一对一绑定
    relation = models.OneToOneField(SupplierBuyerRelation, on_delete=models.CASCADE, primary_key=True)
    discount_rate = models.DecimalField(max_digits=5, decimal_places=2)

class Product(models.Model):
    product_name = models.CharField(max_length=128)
    relation = models.ForeignKey(SupplierBuyerRelation, on_delete=models.CASCADE, related_name="products")
    price = models.DecimalField(max_digits=10, decimal_places=2)

查询代码示例

# 批量查询当前买家可见的商品及对应折扣
products = Product.objects.filter(
    relation__buyer_id=request.user.id
).select_related('relation__discount')

for product in products:
    if hasattr(product.relation, 'discount'):
        discounted_price = product.price * product.relation.discount.discount_rate
    else:
        discounted_price = product.price

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 18:03:03