Django 多外键导航

Posted

技术标签:

【中文标题】Django 多外键导航【英文标题】:Django Multiple ForeignKey Navigation 【发布时间】:2015-02-17 02:03:34 【问题描述】:

我正在构建一个购物车。在我的购物车中,一个项目可以由其他项目组成。我需要在单个模板中显示一组项目及其对应的相关部分。我知道如何在模板中显示单个项目及其对应部分,但我似乎无法弄清楚如何显示多个项目,每个项目都有自己的包含部分列表。

我已经摆弄了模板文件中标签的每一个排列:

# checkout.html

% for item in cart_items %
    <tr>
        <td class="left">
         item.name 
        <ul>
        % for part in item.product.buildpart.part_set.all %
            <li> part.name 
        % endfor %
        </ul>

        </td>
        <td>$ item.price </td>
        <td> item.quantity </td>
        <td class="right">$ item.lineItemTotal </td>
    </tr>
% endfor %

这是生成模板的 vew:

# views.py

def checkout(request):
    cart_items = get_cart_items(request)

    <snip>    

    return render(request, 'checkout.html', locals())

下面是 get_cart_items() 函数,它返回用户购物车中的所有商品:

# cart.py

def get_cart_items(request):
    """ return all items from the current user's cart """
    return CartItem.objects.filter(cart_id=get_cart_id(request))

这是 CartItem 模型:

# models.py

class Item(models.Model):
    cart_id = models.CharField(max_length=50)
    quantity = models.IntegerField(default=1)
    product = models.ForeignKey(PartModel, unique=False)

    class Meta:
        abstract = True

    <snip>

class CartItem(Item):
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['date_added']
        verbose_name = "Cart Item"

    <snip>

“product”字段是 PartModel 模型的 ForeignKey:

# models.py

class PartModel(models.Model):
    family = models.ForeignKey(PartFamily)
    name = models.CharField("Model Name", max_length=50, unique=True)
    slug = models.SlugField(help_text="http://www.Knowele.com/<b>*slug*</b>",
                            unique=True)
    <snip>
    buildpart = models.ManyToManyField('self', through='BuildPart',
                                symmetrical=False, related_name='+')

    class Meta:
        ordering = ['name']
        verbose_name = "Product Model"

    <snip>

PartModel 模型通过 buildpart 字段和 BuildPart 模型与其自身具有多对多关系,以促进可以由其他目录项组成的目录项的概念:

# models.py

class Build(models.Model):
    build = models.ForeignKey(PartModel, related_name='+')
    part = models.ForeignKey(PartModel, related_name='+')
    quantity = models.PositiveSmallIntegerField(default=1)

    class Meta:
        abstract = True
        unique_together = ('build', 'part')

    def __unicode__(self):
        return self.build.name + ' with ' + str(self.quantity) + ' * ' + \
               self.part.family.make.name + ' ' + self.part.name

class BuildPart(Build):
    pass

    class Meta:
        verbose_name = "Build Part"

我似乎无法在模板(上面列出)中进行必要的 ForeignKey 遍历,以便在 CartItem 模型中获取与用户项目关联的所有部分。是我在模板中做的不对还是我没有在我的视图中打包正确的查询集?

这个问题的第二部分是,一旦我得到这些部分,我需要它们按照 PartType 模型的“order”整数字段中指定的顺序显示:

# models.py

class PartType(models.Model):
    name = models.CharField("Part Type", max_length=30, unique=True)
    slug = models.SlugField(unique=True)
    order = models.PositiveSmallIntegerField()
    description = models.TextField(blank=True, null=True)

    class Meta:
        ordering = ['name']
        verbose_name = "Product Type"

    def __unicode__(self):
        return self.name

class PartFamily(models.Model):
    make = models.ForeignKey(PartMake)
    type = models.ForeignKey(PartType)
    name = models.CharField("Family Name", max_length=30,
                             unique=True)
    slug = models.SlugField(unique=True)
    url = models.URLField("URL", blank=True, null=True)
    description = models.TextField(blank=True, null=True)

    class Meta:
        ordering = ['name']
        verbose_name = "Product Family"
        verbose_name_plural = "Product Families"

    def __unicode__(self):
        return self.name

如您所见,在 PartModel 模型中,“family”字段是 PartFamily 模型的 ForeignKey,而在 PartFamily 模型中,“type”字段是 PartType 模型的 ForeignKey,其中是 all - 零件需要订购的重要“订单”字段。

我希望这是有道理的,你会明白为什么这对于像我这样的菜鸟来说如此复杂。

【问题讨论】:

我已经回答了您之前问题的第 1 部分。答案还是一样的;这次你在做buildpart.part_set,但buildpart 仍然是多对多访问器,所以没有part_set 这样的东西,只需遍历buildpart.all 另外,真的不清楚为什么你有所有这些抽象模型,然后你会继承这些模型。重点是什么? BuildPart 应该直接打开字段,然后删除 Build 模型。 感谢丹尼尔·罗斯曼!你让它为我工作!如果您以正常方式重新发布答案,我会给您获胜的答案,以便我可以单击复选标记。 另外,您(或其他人)能否告诉我如何让他们以正确的顺序列出(通过 PartType 模型中的“订单”字段?为了回答您的问题,我需要抽象模型,因为多个模型继承自它们,为了简洁起见,我只是剪掉了这些模型,但它们存在并且我使用它们。你会在我之前的问题中看到这些其他模型。再次感谢! 第二个问题的答案:***.com/questions/6540032/… 【参考方案1】:

只需迭代 item.product.buildpart.all:

% for item in cart_items %
    [...]
    % for part in item.product.buildpart.all %
         part.name [...]
    % endfor %
% endfor %

【讨论】:

以上是关于Django 多外键导航的主要内容,如果未能解决你的问题,请参考以下文章

Django---进阶5

模板中的 Django 和选项卡式导航

django 插入外键值思路

sqlalchemy多外键关联

实体框架:0..1 对多外键约束无法识别?

python SQLAchemy多外键关联