Reputation: 791
I'm trying to pass an object to my HTML template consisting of the parent object and all child objects that relate to it. For instance:
Model Chamber:
class Chamber(models.Model):
chamber_name = models.CharField(max_length=100)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
Has ChamberProperty:
class ChamberProperty(models.Model):
chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
property_name = models.CharField(max_length=50)
property_value = models.CharField(max_length=100)
user_defined = models.BooleanField(default=True)
They are two separate models because the customer can add as many properties as they want to their chamber.
In my views.py
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))
try:
chamber_properties = list(ChamberProperty.objects.filter(chamber__in=chambers_list).order_by('id'))
except:
chamber_properties = "No properties"
form = ChambersFilterForm(request=request)
return render(request, self.template_name, {'filter_form':form, 'chambers_list': chambers_list, 'chamber_properties': chamber_properties})
Now, that does get me a list of all chambers, and a list of all chamber properties. Except they're not linked to each other. I'm not sure how to build a list of related objects. I read about backwards relationships just now, but I don't seem to grasp how to use them.
I tried the following:
chambers_and_props = Chamber.chamberproperty_set.all()
And I get the following error:
AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'all'
So I'm not quite sure how to use it. The threads I saw mentioned that a relationship in Django automatically add a reverse on ForeignKeys and the usage should be parent.child_set.all()
with child
in lower caps.
I get a ReverserManyToOneDescriptor
object, but not sure how to turn that into a usable list I can pass on to my HTML template.
Any ideas as to what I'm doing wrong?
Upvotes: 1
Views: 580
Reputation: 599610
Your query does not work because you have not specified which Chamber you want to get the backwards relation for.
However, this is not the right approach. Presumably you want the ChamberProperty so you can list them against each Chamber in the template. So, you should follow the relationship there in the template - there's no need to query ChamberProperty separately in the view at all.
{% for chamber in chamber_list %}
{{ chamber.chamber_name }}
{% for property in chamber.chamberproperty_set.all %}
{{ property.property_name }} : {{ property.property_value }}
{% endfor %}
{% endfor %}
Upvotes: 2
Reputation: 308849
You are getting the error because you are trying Chamber.chamberproperty_set
on the model Chamber
. It will work on individual chamber
instances:
You can do this in the view:
for chamber in chambers_list
properties = chamber.chamberproperty_set.all()
Or in the template:
{% for chamber in chambers_list %}
{{ chamber }}
{% for property in chamber.chamberproperty_set.all %}
{{ property }}
{% endfor %}
Then, in your view, you can use prefetch_related
to reduce the number of SQL queries:
chambers_list = Chamber.objects.filter(customer=customer).prefetch_related('chamberproperty_set')
Upvotes: 1