superv
superv

Reputation: 45

How to retrieve data in Django model using related name and generic detail views

I am trying to display the data from one of my models to the DetailView using the related name defined in the model. It works for the Rental Property model but it doesn't work for the contract model. What might seems to be the problem?

A little context to what I am trying to achieve. To get the attribute's value of the rental model, I use a for loop on landlord.rentalproperty.all; rentalproperty been the related name to the landlord model. This work perfectly.

Where I am having a problem is when I use the contract model related name to rentalproperty, this doesn't work. How can I fixed that? Thanks.

my model:

UserModel = get_user_model()

class Landlord(models.Model):
    user = models.OneToOneField(UserModel, on_delete=models.CASCADE)
    address = models.CharField(max_length=255)

    def __str__(self):
        return str(self.address)


class RentalProperty(models.Model):
    landlord = models.ForeignKey("Landlord", related_name='rentalproperty', on_delete=models.CASCADE)
    created_by = models.ForeignKey(UserModel, related_name='rentalproperty', on_delete=models.CASCADE)

    PROPERTY_LISTING_CHOICES = Choices(
        ('APARTMENT', _('Apartment')),
        ('HOLIDAY_HOME', _('Holiday home')),
        ('SINGLE_FAMILY_HOME', _('Single family home')),
        ('COMMERCIAL', _('Commercial')),
    )
    type_of_property_listing = models.CharField(
        max_length = 50,
        choices = PROPERTY_LISTING_CHOICES,
        default = PROPERTY_LISTING_CHOICES.APARTMENT,)

    street = models.CharField(max_length=255)
    borough = models.CharField(max_length=255)

    def __str__(self):
        return str(self.type_of_property_listing)

class Contract(models.Model):
    rentalproperty = models.ForeignKey("RentalProperty", related_name='contracts', on_delete=models.CASCADE)
    insurance_required = models.BooleanField(default=True)
    other_terms = models.TextField(blank=True)

    def __str__(self):
        return str(self.insurance_required)

My html:

 <h1>This is the detail view</h1>
    <h3>From landlord</h3>
    <p>Address: {{landlord.address}}</p>
    <h3>From Rental property</h3>
    <ul>
    {% for rental in landlord.rentalproperty.all %}
    <li>landlord: {{rental.landlord}}</li>
    <li>createdby: {{rental.created_by}}</li>
    <li>Type of property: {{rental.type_of_property_listing}}</li>
    <li>Street: {{rental.street}}</li>
    <li>Borough: {{rental.borough}}</li>
    {% endfor %}
    </ul>

    <ul>
    {% for contract in rentalproperty.contracts.all %}
    <li> rental property: {{contract.rentalproperty}}</li>
    {% endfor %}
    </ul>

My detail View.

class DetailView(generic.DetailView):
    model = Landlord
    template_name = 'rental/detail.html'

Upvotes: 0

Views: 886

Answers (1)

Aerials
Aerials

Reputation: 4419

Here's a DetailView view:

class RentalPropertyDetailView(DetailView):
    context_object_name = 'property'
    model = models.RentalProperty

Notice the "context_object_name" attribute.

Second, your template is a little confusing.. Why would you want to loop for one landlord, listing the landlord's name again for each of its rental properties. And the the same for each contract?

Here's arentalproperty_detail.html template:

<h1>This is the detail view</h1>
<h3>From landlord: {{ property.created_by }}</h3>
<p>Address: {{ property.landlord.address }}</p>
<h3>From Rental property</h3>
<ul>
    {% for rental in property.landlord.rental_properties.all %}
    <br>
    <li>createdby: {{rental.created_by}}</li>
    <li>Type of property: {{rental.type_of_property_listing}}</li>
    <li>Street: {{rental.street}}</li>
    <li>Borough: {{rental.borough}}</li>
    <ul>
        {% for contract in rental.contracts.all %}
        <li> Insurance required: {{contract.insurance_required}}</li>
        {% endfor %}
    </ul>
    {% endfor %}
</ul>

Now a models.py:

class RentalProperty(models.Model):
    landlord = models.ForeignKey("Landlord", related_name='rental_properties', on_delete=models.CASCADE)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)

    PROPERTY_LISTING_CHOICES = [
        ('APARTMENT', ('Apartment')),
        ('HOLIDAY_HOME', ('Holiday home')),
        ('SINGLE_FAMILY_HOME', ('Single family home')),
        ('COMMERCIAL', ('Commercial')),
    ]
    type_of_property_listing = models.CharField(
            max_length = 50,
            choices = PROPERTY_LISTING_CHOICES,
            default = 'APARTMENT',
        )

    street = models.CharField(max_length=255, default=None, null=True)
    borough = models.CharField(max_length=255, default=None, null=True)

    def __str__(self):
        return str(self.type_of_property_listing)


class Contract(models.Model):
    rental_property = models.ForeignKey("RentalProperty", related_name='contracts', on_delete=models.CASCADE)
    insurance_required = models.BooleanField(default=True)
    other_terms = models.TextField(blank=True)

    def __str__(self):
        return str(self.insurance_required)

The Landlord model I left it the same.

In urls.py you should fetch one (1) RetailProperty like:

url(r'^property/(?P<pk>\d+)$', views.RentalPropertyDetailView.as_view(), name='property-detail'),

This will output the following:

enter image description here

Upvotes: 2

Related Questions