【问题标题】:Query and paginate three types of models at the same time in django在django中同时查询和分页三种模型
【发布时间】:2010-01-08 05:55:33
【问题描述】:

在 django 中我有三个模型:

  • 简单产品
  • ConfigurableProduct 用户将看到一个带有颜色等选项的产品,而不是显示 SimpleProducts 的多个变体。
  • GroupProduct - 几个一起销售的 SimpleProduct。

首先我创建所有的 SimpleProducts,然后我从几个作为同一产品变体的产品创建 ConfigurableProducts,最后是 GroupProducts,它们是几个 SimpleProducts 的组合。

当用户导航到一个类别时,我需要向他展示所有三种类型。如果 SimpleProduct 是 ConfigurableProduct 的一部分,我不想显示两次。

如何进行查询?我必须创建三个查询吗? 如何同时在三个模型上使用分页? 我可以以某种方式使用继承吗?

谢谢

【问题讨论】:

    标签: django pagination django-queryset


    【解决方案1】:

    如果不更清楚地了解您的业务逻辑,我认为这个问题很难回答。以下是我的假设:

    1. 可配置选项是临时性的,即您出售红色、蓝色和黄色的球,以及小、中、大号的衬衫等。无法抽象地表示这些选项,因为它们不超越类别。 (如果他们这样做了,那么您的数据库设计就是错误的。如果所有内容都有自定义颜色选项,您只需将其作为数据库表中的一列。)
    2. 每个配置选项在您的公司都有一个预先存在的业务标识。有一些 sku 与红球或类似的东西有关。无论出于何种原因,每个可能的配置选项都必须有一个数据库行。 (如果不是,那么你又做错了。)

    如果是这种情况,我最简单的建议是使用一些基类,所有产品都从其中继承一个字段:representative_product_id。这个想法是,对于每个产品,都有一个代表版本显示在类别页面或目录中的任何其他位置。在您的数据库中,这将如下所示:

    Name          id    representative_id
    red_ball      1     1
    blue_ball     2     1
    green_ball    3     1
    small_shirt   4     4
    medium_shirt  5     4
    large_shirt   6     4
    unique_thing  7     7
    

    对于 django 查询,如果您有 1.1 或更高版本,我会使用 F objects。只是:

    SimpleProduct.objects.filter(representative_id=F('id'))
    

    这将返回一个查询集,其代表 id 与他们自己的 id 匹配。

    此时,有人会要求数据完整性。主要条件是representative_id 在所有情况下都必须指向一个representative_id 与其id 匹配的对象。有一些方法可以直接执行此操作,例如使用 pre_save 验证器或类似的东西。您也可以通过分解包含representative_id 列的ProductType 表来有效地做同样的事情。即:

    Products
    Name          id    product_type
    _________________________________
    red_ball      1     ball
    blue_ball     2     ball
    green_ball    3     ball
    small_shirt   4     shirt
    medium_shirt  5     shirt
    large_shirt   6     shirt
    unique_thing  7     thing
    
    Types
    Name          representative_id
    _______________________________
    ball          1
    shit          4
    thing         7
    

    这并不能取代使用某些验证器来强制执行完整性的需要,但它使它更加抽象。

    【讨论】:

    • 这是一个有趣的设计。我不明白您建议的查询: SimpleProduct.objects.filter(representative_id=F('id')) 当我查询数据库时,我需要使用分页,所以我需要知道 red_ball 和 blue_ball 算作一个产品有一个选择框,但如果只有 red_ball 我仍然显示它。
    • 是的,这会发生。此查询所做的只是返回代表其类型的项目。如果该项目与任何其他项目无关,那很好,只需确保默认情况下代表_id = id。这是一种投影映射:给定一组产品,过滤到代表它们自己类型的产品。
    【解决方案2】:

    使用 Django 的 multi-table inheritance,使用不会直接实例化的基类。基类仍然有一个可以运行查询的管理器,它将包含任何子类实例的基本属性。

    为了解决您关于不可重复显示的可配置产品的问题,我认为您有两种选择:

    • 使可配置产品成为 ConfigurableProductChoice 的多项选择(与 SimpleProduct 无关)。让 ConfigurableProductChoice 扩展 ConfigurableProduct。这样一来,您的结果中就会有一个 ConfigurableProduct 并且没有冗余。
    • 使可配置产品与各种选项相关联,并设计一个规则来根据选择的选项计算价格。一个简单的添加就可以了。您的产品 ID 需要对选择的选项进行编码。您仍然没有冗余,因为您没有涉及 SimpleProduct。

    【讨论】:

    • 所以我创建了一个带有产品名称和描述的基类(不是抽象的)。然后我有 SimpleProduct 和 ConfigurableProduct 来扩展它。我在基本产品模型上进行查询和分页。当我在模板中显示结果时,django 会因为我使用继承而对每个对象进行单独的查询?
    • 是的,除了最后 Django 只做一个查询。查询是在表示基类的数据库表上进行的,它产生基类的实例。如果方便的话,您可以添加一个基本方法来获取子实例,但这需要额外的查询。
    • 因为这张票 code.djangoproject.com/ticket/7270 我将不得不进行 n+1 次查询。也许有办法用 __in 查询来欺骗它?
    • 我不知道。根据您的设计,基类查询就足够了。您可以将一个小的 html sn-p 缓存在内存中,以更具体地在列表中表示产品。
    • 我认为这是一个非常糟糕的主意,因为它会生成大量查询。我有 django 站点不正确地使用继承的经验,它不仅会导致 n+1 查询,还会导致 1+n^2 查询,甚至更糟。有时会使用继承,但不是分页。
    猜你喜欢
    • 1970-01-01
    • 2017-11-25
    • 2011-01-08
    • 2012-08-27
    • 1970-01-01
    • 2015-07-03
    • 2018-08-30
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多