Django多个ForeignKey导航

时间:2014-12-18 10:06:12

标签: python django django-templates

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

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

# 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 %}

以下是生成模板的视图:

# 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模型与其自身具有ManyToMany关系,以便于可以由其他目录项组成的目录项的概念:

# 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模型中用户项目相关的所有部分。这是我在模板中做得不对的,还是我没有在我的视图中打包出正确的QuerySet?

这个问题的第二部分是,一旦我得到这些部分,我需要它们按照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 个答案:

答案 0 :(得分:1)

只需迭代item.product.buildpart.all

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