Search code examples
djangodjango-modelsdjango-templatesforeign-keys

Django Accessing Child Data in Templates from Parent object


I am new to Django and am trying to do something that should be very straightforward (in my mind) but I've spent a few hours on this and haven't solved it yet.

Goal: Within a template, I would like to get a value from a field from a child object using the parent. In this case, I am trying to get the lab_request object by knowing the parent sample.

So far I have tried using both a ForeignKey in the Lab_Request model as well as an OneToOneField

A specific area in the code where I believe I am going wrong is {{ sample.lab_request.placeholder_to_be_replaced }}. Sample is a parent and 'Lab_Requests' is a child. In this case, I have set it to OneToOneField but really I have this issue in another area where it will be a Parent to multiple Children.

Code:

#models.py

class Sample(models.Model):

    order = models.ForeignKey(Order, on_delete=models.CASCADE)
   status = models.CharField(max_length=2, choices=SAMPLE_STATUS_OPTIONS, default="01")
    sample_number = models.CharField(max_length=19, unique=True, editable=False, default=get_sample_number)



class Inspection_Request(models.Model):
    #Add stuff here
    placeholder_to_be_replaced = models.CharField(max_length=1)
    sample = models.OneToOneField(Sample, on_delete=models.CASCADE)
    inspector = models.OneToOneField(Inspector, on_delete=models.CASCADE, null=True, blank=True)


class Lab_Request(models.Model):
    #Add stuff here
    placeholder_to_be_replaced = models.CharField(max_length=1)
    sample = models.OneToOneField(Sample, on_delete=models.CASCADE)
    inspector = models.OneToOneField(Inspector, on_delete=models.CASCADE, null=True, blank=True)

#views.py

class SampleHomeView(ListView):
    model = Sample
    samples = Sample.objects.all
    context_object_name = 'samples'
    template_name = '<app name>/sample.html'
    ordering = ['-sample_date']
    paginate_by = 10

#sample.html

{% extends 'base.html' %}
{% block content %}
{% load custom_tags %}
{% load define_action %}
<h1>Sample Status</h1>

#other stuff that doesn't matter

            {% for sample in samples %}
                {% if user.profile.employee.pk == sample.inspector.employee.pk or perms.ics.view_sample %}
                                    <tr>
                                        <td class="column1">{{ sample.sample_date }}</td>
                                        <td class="column2">{{ sample.status|sample_status_options }}</td>
                                        <td class="column3"><a href="#">{{ sample.sample_number }}</a></td>
                                        <td class="column4"><a href="#">{{ sample.order.customer.customer_name }}</a></td>
                                        <td class="column5"><a href="#">{{ sample.lab_request.placeholder_to_be_replaced }}{{ sample.lab_request.lab.lab_name }}{{ sample.inspection_request.inspector.employee.employee_first_name }}</a></td>
                                        <td class="column6">{{ sample.date_modified|date:'F d, Y'  }}</td>
                                    </tr>
                {% endif %}
            {% endfor %}


#more stuff that doesn't matter

{% block table %}
{% endblock table %}

{% endblock content %}

Any guidance would be appreciated.


Solution

  • OK I figured it out. I needed to call the child to the parent slightly differently than I was doing. I need to use {{ sample.lab_request_set.all.0.lab }} instead of the {{ sample.lab_request.lab }}

    For anyone that needs this in the future, if you do not set a related name in the ForeignKey then it will be parent_model_name.child_model_name_set.all this will give you a query set that you can then iterate through or just select the first like I did with the .0 at the end of the .all. This works in a template. If you need it in a python file then you will be calling the function with parent_model_name.child_model_name_set.all()