pyrodney
pyrodney

Reputation: 370

Django template sort by 'unrelated' model's field

I'm trying to sort related items in a template by a field in a model three ForeignKey relationships away. I'm assembling the data for the template in the view as proposed in another StackOverflow answer:

Sorting related items in a Django template

As far as I can tell, I copied the code from this as-is except for I had to change variable names. It doesn't throw an error, it just displays no list items in the HTML unordered list.

# checkout.html

{% for item in cart_items %}
    <tr>
        <td class="left">
        {{ item.name }}
        <ul>
        {% for part in part_list %}
            <li>{{ part.name }}
        {% endfor %}
        </ul></td>
    </tr>
{% endfor %}

And the view...

# views.py

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

    itemCollection = []   
    for item in cart_items:
       item.part_list = item.product.buildpart.all().order_by('product__family__type')
       itemCollection.append(item)

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

And the get_cart_items function:

# 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))

As I said, the template and view are pretty much copies of the solution presented in the aforementioned StackOverflow article. One thing I thought was curious was that itemCollection[] from the view is never referenced in the template.

I believe the order_by clause ('product__family__type') is right only because it doesn't generate an error. But in case that is the problem or a part of it here is the chain of models I am attempting to navigate in that order_by clause:

We start from the shopping cart model (CartItem):

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

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

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

Through the 'product' field we get to the model holding our inventory and its self-referential BuildPart ManyToMany model:

class PartModel(models.Model):
    family = models.ForeignKey(PartFamily)
    name = models.CharField("Model Name", max_length=50, unique=True)
    buildpart = models.ManyToManyField('self', through='BuildPart',
                                symmetrical=False, related_name='+')

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"

From there we follow the 'family' field to the PartFamily model:

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)

And lastly, we get to the model with the 'order' field, the one we wish to sort the related items by, PartType:

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)

To recap, how do I get the shopping cart products' related items, and sort them by the 'order' field in the PartType model?

Upvotes: 0

Views: 237

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599490

You have two errors, both in the template.

Firstly, you've put your items with the sorted relationship in a list called itemCollection, but in the template you're iterating over cart_item instead. This is a very good example of why you should be explicit about what variables you pass to the template, rather than relying on locals().

Secondly, you then iterate over part_list without defining it. You mean item.part_list.

Upvotes: 1

Related Questions