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

Django多模型跨表查询求助:获取产品套餐关联价格

问题:获取套餐内产品的关联价格数据(Django ORM)

开发活动销售系统,events、products、price模型功能正常。当前bundle(产品套餐)模型关联多个产品,已获取当前查看产品对应的套餐列表,需通过Django ORM实现跨模型查询,获取套餐内产品的关联价格数据。

模型代码

from events.models import events
import uuid
import datetime


class products(models.Model):
    id                          = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False, verbose_name="ProductID")
    name                        = models.CharField(max_length=255, verbose_name="Product Name")
    linkedtoevent               = models.ForeignKey(to=events, on_delete=models.CASCADE, verbose_name="Linked Event ID")
 
    def __str__(self):
        return self.name


class price(models.Model):
    id                          = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False, verbose_name="PriceRecordID")
    productid                   = models.ForeignKey(to=products, on_delete=models.CASCADE)
    price                       = models.FloatField(verbose_name="price")
    date_from                   = models.DateField(verbose_name="Date From")
    date_to                     = models.DateField(verbose_name="Date To")
    
    @property
    def status(self):
        today = datetime.date.today()
        # 注:原逻辑仅判断当天等于date_from或date_to,建议改为date_from<=today<=date_to
        if today in (self.date_to, self.date_from):
            return True
        else: return False


class bundle(models.Model):
    id                          = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False)
    name                        = models.CharField(max_length=255, verbose_name="Product Name")
    productsinbunble            = models.ManyToManyField(products)
    date_from                   = models.DateField(verbose_name="Date To")  # 注:verbose_name与字段名反向,建议修正
    date_to                     = models.DateField(verbose_name="Date From")  # 注:同上
    discount                    = models.FloatField(verbose_name="Discount")
    
    def __str__(self):
        return self.name

解决方案及解释

1. 获取套餐+关联产品+所有价格记录

使用prefetch_related处理多对多关系,搭配Prefetch自定义关联查询:

from django.db.models import Prefetch

# 假设current_product是当前查看的产品实例
bundles = bundle.objects.filter(productsinbunble=current_product).prefetch_related(
    Prefetch(
        'productsinbunble__price_set',
        queryset=price.objects.all(),
        to_attr='all_prices'
    )
)

# 遍历使用示例
for bundle_obj in bundles:
    print(f"套餐:{bundle_obj.name}")
    for product in bundle_obj.productsinbunble.all():
        print(f"产品:{product.name}")
        for price_obj in product.all_prices:
            print(f"价格:{price_obj.price},有效期:{price_obj.date_from}至{price_obj.date_to}")

2. 获取套餐+关联产品+当前有效价格

如果仅需要当前生效的价格(建议将status逻辑修正为date_from<=当天<=date_to),直接在Prefetch中过滤:

from django.db.models import Prefetch
import datetime

today = datetime.date.today()
bundles = bundle.objects.filter(productsinbunble=current_product).prefetch_related(
    Prefetch(
        'productsinbunble__price_set',
        queryset=price.objects.filter(date_from__lte=today, date_to__gte=today),
        to_attr='active_prices'
    )
)

# 遍历使用示例
for bundle_obj in bundles:
    print(f"套餐:{bundle_obj.name}")
    for product in bundle_obj.productsinbunble.all():
        print(f"产品:{product.name}")
        for price_obj in product.active_prices:
            print(f"当前有效价格:{price_obj.price}")

3. 从产品反向查询套餐及关联价格

若已持有当前产品实例,可通过反向关联直接查询套餐:

from django.db.models import Prefetch
import datetime

today = datetime.date.today()
current_product = products.objects.get(id="你的产品ID")

# 反向关联名称默认是`bundle_set`(因未设置related_name)
bundles = current_product.bundle_set.all().prefetch_related(
    Prefetch(
        'productsinbunble__price_set',
        queryset=price.objects.filter(date_from__lte=today, date_to__gte=today),
        to_attr='active_prices'
    )
)

关键要点

  • 多对多反向关联:products模型未给bundle的productsinbunble字段设置related_name,Django默认生成bundle_set作为反向关联名称。
  • 避免N+1查询:prefetch_related用于处理多对多、反向外键这类跨表关联,一次性预加载关联数据,替代多次查询。
  • 自定义关联查询:Prefetch对象允许指定过滤后的查询集,还能通过to_attr设置别名,方便后续调用。
  • 状态过滤优化:因status是模型属性,无法直接用于ORM过滤,需直接用日期条件date_from__lte=today, date_to__gte=today实现相同逻辑(原status逻辑仅判断当天等于起止日期,存在逻辑漏洞,建议修正)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 19:01:20