Search code examples
djangodjango-modelsdjango-templatesdjango-template-filters

How can I template filter backwards two different models?


I've got three models, "Property", "Owners" and "ContactsOwner", these last one is where I save the owners contacts.

# APP: Owners - models.py
    class Owner(models.Model):
        name = models.CharField(db_column='Owner_Name', max_length=200)
        surname = models.CharField(db_column='Owner_Surname', max_length=30)
        nif = models.IntegerField(db_column='Nif_Number', blank=False, null=False, default='000000000')
        doc_number = models.CharField(db_column='Document_Number', max_length=20, blank=True, null=True)
        doc_type = models.CharField(db_column='Document_Type', max_length=20, blank=True, null=True, choices=DOCUMENT_TYPE_CHOICES)
        address = models.CharField(db_column='Address', max_length=200, blank=True, null=True)
        post_code = models.CharField(db_column='Post_Code', max_length=15, blank=True, null=True)
        nationality = models.CharField(db_column='Country', max_length=20, blank=True, null=True)
        notes = models.CharField(db_column='Notes', max_length=250, blank=True, null=True)
        property = models.ManyToManyField(Property)


        class Meta:
            db_table = 'Owner'

        def __str__(self):
            return self.name

        def get_absolute_url(self):
            return reverse("owners:owner_detail",kwargs={'pk':self.pk})

    class ContactsOwner(models.Model):
        owner = models.ForeignKey(Owner, models.DO_NOTHING, db_column='Owner', related_name='owner_contact')  # Field name made lowercase.
        type = models.CharField(db_column='Type', choices=CONTACT_TYPE_CHOICES, max_length=25, blank=True, null=True)  # Field name made lowercase.
        number = models.IntegerField(db_column='Number', blank=True, null=True)  # Field name made lowercase.
        email = models.CharField(db_column='Email', max_length=100, blank=True, null=True)  # Field name made lowercase.

        class Meta:
            db_table = 'Contacts_Owner'
            verbose_name_plural = "Owners Contacts"


# APP: Properties - models.py
class Property(models.Model):
    property_reference = models.CharField(db_column='Property_Reference', max_length=10)  # Field name made lowercase.
    address = models.CharField(db_column='Address', max_length=250, blank=True, null=True)  # Field name made lowercase.
    post_code = models.CharField(db_column='Post_Code', max_length=15, blank=True, null=True)  # Field name made lowercase.
    type = models.CharField(db_column='Type', max_length=25, blank=True, null=True, choices=HOUSE_TYPE_CHOICES)  # Field name made lowercase.
    bedrooms = models.IntegerField(db_column='Bedrooms', blank=True, null=True)  # Field name made lowercase.
    bathrooms = models.IntegerField(db_column='Bathrooms', blank=True, null=True)  # Field name made lowercase.
    usual_cleaning_requirements = models.CharField(db_column='Usual_Cleaning_Requirements', max_length=250, blank=True, null=True)  # Field name made lowercase.
    notes = models.CharField(db_column='Notes', max_length=500, blank=True, null=True)  # Field name made lowercase.
    feature_image = models.ImageField(null=True)

    class Meta:
        db_table = 'Property'

    def __str__(self):
        return self.property_reference

    def get_absolute_url(self):
        return reverse("properties:property_detail",kwargs={'pk':self.pk})

In my template I can access the Owner name and surname with this loop:

{% for object in property.owner_set.all %}
  <h4>{{ object.name }} {{ object.surname }}</h4>
  <h6>Owner</h6>
{% endfor %}

But now I need to access the contact number on "ContactsOwner" model and I can't figure out a way to filter this.

I've tried these:

{% for contact in property.owner_set.owner_contact.all %}
   <div class="card-body border-top">
      {{ contact.number }}
      <br>
   </div>
{% endfor %}

But so far I didn't find a solution. Could you please help me with this?


Solution

  • You can not access a related manager of a related manager, you can use a double {% for ... %} loop here, but this is not advisable:

    {% for owner in property.owner_set.all %}
      {% for contact in owner.owner_contact.all %}
      <div class="card-body border-top">
        {{ contact.number }}
        <br>
      </div>
      {% endfor %}
    {% endfor %}

    It is better to perform queries in the view, since that is mainly business logic. You can retrieve all OwnerContacts for a given property with:

    ContactsOwner.objects.filter(owner__property=property)