Reputation: 791
I have two models that are related, and I need to create a table that takes from both objects.
In my models:
class Chamber(models.Model):
chamber_name = models.CharField(max_length=100)
chamber_type = models.CharField(max_length=50)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class ChamberProperties(models.Model):
chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
property_name = models.CharField(max_length=20)
property_value = models.CharField(max_length=100)
The structure is strange, but it's too late to just add properties and values to the chamber model. I'll have to live with the fact that they are two separate models.
In my table I need the following structure:
chamber_name(obj A) - property_value(obj B) - customer(obj A again)
I tried zipped lists, but I don't seem to be able to unpack it:
class ChambersView(generic.DetailView):
template_name = 'pages/chambers.html'
def get(self, request):
user = User.objects.get(username=request.user)
customer = Customer.objects.get(user=user)
chambers_list = list(Chamber.objects.filter(customer=customer))
chamber_properties = list(ChamberProperties.objects.filter(chamber__in=chambers_list).order_by('id'))
objects_list = zip(chamber_properties, chambers_list)
form = ChambersFilterForm(request=request)
return render(request, self.template_name, {'filter_form':form, 'objects_list': objects_list})
If I unpack it in python it works:
for properties, chambers in objects_list:
print("-----------------------------------------------------------")
print("Property is: ", properties.property_value, "and the chamber is:", chambers.chamber_name)
print("-----------------------------------------------------------")
But when I go to my HTML template:
<div class="card-body p-1">
<table class="table table-hover">
<tr class="table-active">
<th>Chamber</th>
<th>Property Value</th>
<th>Customer</th>
</tr>
{% for properties, chambers in objects_list %}
<tr>
<td><a href="{% url 'chamber' chamber.id %}">{{chambers.chamber_name}}</a></td>
<td><a href="{% url 'chamber' chamber.id %}">{{properties.property_value}}</a></td>
<td><a href="{% url 'chamber' chamber.id %}">{{chambers.customer}}</a></td>
</tr>
{% endfor %}
</table>
</div>
The table comes up empty. There are no errors, no logs, the server works fine. If I just do {{ objects_list }} outside of the for-loop I get "zip object at " in the HTML. So I know something is there. I just don't seem to be unpacking it properly because if I do {{objects_list}} inside the for loop, again nothing shows up.
Any ideas? I would greatly appreciate any help in this matter. As a junior, I've searched around and I've seen some people override "get_context_data" for similar cases, but I wouldn't know how to do that yet or if it would be usable for this case.
Upvotes: 4
Views: 1808
Reputation: 3828
So, in python 2.7 it looks like zip
immediately returns a list of tuples. In python 3 (which I'm guessing you're using), zip
will return a zip
class.
print(zip([1,2,3],[4,5,6]).__class__)
<class 'zip'>
Django's templating language might not know what to do with that and it bails out on even trying to iterate. Django's templating language is also very quiet when it runs into problems like that, almost sometimes to a fault IMO.
An easier way to convert it than the comprehension I put in the comments above would be wrapping it in a list()
call:
objects_list = list(zip(chamber_properties, chambers_list))
Upvotes: 2