I'm building a shopping cart. In my shopping cart an item can be composed of other items. I need to display a set of items with their corresponding associated parts in a single template. I know how to show a single item with its corresponding parts in a template, but I can't seem to figure out how to show more than one item, each with its own list of included parts.
I have fiddled with every permutation of tags in the template file:
# 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 %}
Here is the vew that generates the template:
# views.py
def checkout(request):
cart_items = get_cart_items(request)
<snip>
return render(request, 'checkout.html', locals())
And here's the get_cart_items() function that returns all the items in the user's shopping cart:
# 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))
Here's the CartItem model:
# 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>
The 'product' field is a ForeignKey to the PartModel model:
# 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>
The PartModel model has a ManyToMany relationship with itself through the buildpart field and the BuildPart model to facilitate the notion of catalog items that can be composed of other catalog items:
# 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"
I can't seem to make the necessary ForeignKey traversals in the template (listed above) in order to get all the parts associated with the user's items in the CartItem model. Is it something I'm not doing right in the template or am I not packaging up the right QuerySets in my view?
The second part of this issue is that once I get those parts, I need them to show up in the order specified in the 'order' integer field of the PartType model:
# 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
So as you can see, in the PartModel model, the 'family' field is a ForeignKey to the PartFamily model, and in the PartFamily model the 'type' field is a ForeignKey to the PartType model, within which is the all-important 'order' field that the parts need to be ordered by.
I hope this makes sense and you can see why this is so complicated for a noob like me.