如何将具有多个关系的查询集数据传递给Django中的模板

时间:2019-06-28 11:50:47

标签: python django dictionary django-templates django-views

我正在一个项目中使用具有多个OneToOneOneToMany关系的模型。主要模型Listing有4个其他模型,其中根据类型将其引用为OneToOne模型。另一个模型ListingImages模型与OneToMany模型具有Listing关系。因此,我想将Listing模型的数据以及ListingImages和其他4个模型的其他任何相关数据传递给模板。为了清楚地理解这一点,请参见附件中的代码:

models.py

    from django.db import models
from django.contrib.auth.models import User
from location_field.models.plain import PlainLocationField
from PIL import Image
from slugify import slugify
from django.utils.translation import gettext as _
from django.core.validators import MaxValueValidator, MinValueValidator
from listing_admin_data.models import (Service, SubscriptionType, PropertySubCategory,
        PropertyFeatures, VehicleModel, VehicleBodyType, VehicleFuelType,
        VehicleColour, VehicleFeatures, BusinessAmenities, Currency
    )


def current_year():
    return datetime.date.today().year

def max_value_current_year(value):
    return MaxValueValidator(current_year())(value)


class Listing(models.Model):
    listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]

    listing_title = models.CharField(max_length=255)
    listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
    status = models.BooleanField(default=False)
    featured = models.BooleanField(default=False)
    city = models.CharField(max_length=255, blank=True)
    location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    expires_on = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(User,
        on_delete=models.CASCADE, editable=False, null=True, blank=True
    )
    listing_owner = models.ForeignKey(User,
        on_delete=models.CASCADE, related_name='list_owner'
    )

    def __str__(self):
        return self.listing_title


def get_image_filename(instance, filename):
    title = instance.listing.listing_title
    slug = slugify(title)
    return "listings_pics/%s-%s" % (slug, filename)


class ListingImages(models.Model):
    listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
    image_url = models.ImageField(upload_to=get_image_filename,
                              verbose_name='Listing Images')
    main_image = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "Listing Images"

    def __str__(self):
        return f'{self.listing.listing_title} Image'


class Subscriptions(models.Model):
    subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
    subscription_date = models.DateTimeField(auto_now_add=True)
    subscription_amount = models.DecimalField(max_digits=6, decimal_places=2)
    subscribed_by = models.ForeignKey(User, on_delete=models.CASCADE)
    duration = models.PositiveIntegerField(default=0)
    listing_subscription = models.ManyToManyField(Listing)
    updated_at = models.DateTimeField(auto_now=True)
    status = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "Subscriptions"

    def __str__(self):
        return f'{self.listing.listing_title} Subscription'


class Property(models.Model):
    sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
    fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]

    listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
    sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
    for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
    bedrooms = models.PositiveIntegerField(default=0)
    bathrooms = models.PositiveIntegerField(default=0)
    rooms = models.PositiveIntegerField(default=0)
    land_size = models.DecimalField(max_digits=10, decimal_places=2)
    available_from = models.DateField()
    car_spaces = models.PositiveIntegerField(default=0)
    fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
    desc = models.TextField()
    property_features = models.ManyToManyField(PropertyFeatures)
    price = models.DecimalField(max_digits=15, decimal_places=2)
    currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = "Properties"

    def __str__(self):
        return f'{self.listing.listing_title}'


class Vehicle(models.Model):
    sale_hire_choices = [('S', 'Sale'), ('H', 'Hire')]
    transmission_choices = [('A', 'Automatic'), ('M', 'Manual')]
    drive_choices = [('L', 'Left'), ('R', 'Right')]
    condition_choices = [('L', 'Locally Used'), ('F', 'Foreign Used'), ('N', 'Brand New')]
    interior_choices = [('C', 'Cloth'), ('L', 'Leather'), ('O', 'Other')]

    listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
    for_sale_hire = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
    # year_of_manufacture = models.PositiveIntegerField()
    year_of_manufacture = models.IntegerField(_('year'), validators=[MinValueValidator(1900), max_value_current_year])
    engine_capacity = models.PositiveIntegerField()
    model = models.ForeignKey(VehicleModel, on_delete=models.CASCADE)
    description = models.TextField()
    transmission = models.CharField(choices=transmission_choices, max_length=1, default=None)
    drive = models.CharField(choices=drive_choices, max_length=1, default=None)
    current_millage = models.PositiveIntegerField(validators=[MinValueValidator(0)])
    condition = models.CharField(choices=condition_choices, max_length=1, default=None)
    interior = models.CharField(choices=interior_choices, max_length=1, default=None)
    number_of_doors = models.PositiveIntegerField(default=0)
    body_type = models.ForeignKey(VehicleBodyType, on_delete=models.CASCADE)
    fuel_type = models.ForeignKey(VehicleFuelType, on_delete=models.CASCADE)
    colour = models.ForeignKey(VehicleColour, on_delete=models.CASCADE)
    vehicle_features = models.ManyToManyField(VehicleFeatures)
    asking_price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.listing.listing_title}'


class Business(models.Model):
    listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
    service = models.ForeignKey(Service, on_delete=models.CASCADE)
    business_name = models.CharField(max_length=100)
    slogan = models.CharField(max_length=255)
    desc = models.TextField()
    website_address = models.CharField(max_length=50)
    email_address = models.EmailField(max_length=50)
    business_amenities = models.ManyToManyField(BusinessAmenities)
    contact = models.CharField(max_length=15)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = "Businesses"

    def __str__(self):
        return f'{self.listing.listing_title}'

views.py

    from django.shortcuts import render
from listings.models import Listing

def index(request):
    listings = Listing.objects.filter(status=True).prefetch_related("listingimages_set").all()
    context = {
        'listing': [
            {
                'title': listing.listing_title,
                'listing_type': listing.listing_type,
                'featured': listing.featured,
                'city': listing.city,
                'images': list(listing.listingimages_set.all()),
            } for listing in listings
        ]
    }

    return render(request, 'base/index.html', context)

index.html

<!--Featured listings section start-->
<div class="property-section section pt-100 pt-lg-80 pt-md-70 pt-sm-60 pt-xs-50 pb-60 pb-lg-40 pb-md-30 pb-sm-20 pb-xs-10">
    <div class="container">

        <!--Section Title start-->
        <div class="row">
            <div class="col-md-12 mb-60 mb-xs-30">
                <div class="section-title center">
                    <h1>New Listings</h1>
                </div>
            </div>
        </div>
        <!--Section Title end-->

        <div class="row">

            {% for listing in listings %}
                {% if listing.listing_type == 'P' %}
                    <!--Listing start-->
                    <div class="property-item col-lg-3 col-md-6 col-12 mb-40">
                        <div class="property-inner">
                            <div class="image">
                                <a href="single-properties.html"><img src="{% static 'base/assets/images/property/property-1.jpg' %}" alt=""></a>
                                <ul class="property-feature">
                                    <li>
                                        <span class="area"><img src="{% static 'base/assets/images/icons/area.png' %}" alt="">{{ listing.property.land_size }} SqFt</span>
                                    </li>
                                    <li>
                                        <span class="bed"><img src="{% static 'base/assets/images/icons/bed.png' %}" alt="">{{ listing.property.bedrooms }}</span>
                                    </li>
                                    <li>
                                        <span class="bath"><img src="{% static 'base/assets/images/icons/bath.png' %}" alt="">{{ listing.property.bathrooms }}</span>
                                    </li>
                                    <li>
                                        <span class="parking"><img src="{% static 'base/assets/images/icons/parking.png' %}" alt="">{{ listing.property.car_spaces }}</span>
                                    </li>
                                </ul>
                            </div>
                            <div class="content">
                                <div class="left">
                                    <h3 class="title"><a href="single-properties.html">{{ listing.title }}</a></h3>
                                    <span class="location"><img src="{% static 'base/assets/images/icons/marker.png' %}" alt="">{{ listing.city }}</span>
                                </div>
                                <div class="right">
                                    <div class="type-wrap">
                                        <span class="price">Kshs {{ listing.property.price }}</span>
                                        <span class="type">{{ listing.property.get_for_sale_rent_display }}</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--Listing end-->
                {% elif listing.listing_type == 'V' %}
                    <!--Listing start-->
                    <div class="property-item col-lg-3 col-md-6 col-12 mb-40">
                        <div class="property-inner">
                            <div class="image">
                                <a href="single-properties.html"><img src="{% static 'base/assets/images/property/property-1.jpg' %}" alt=""></a>
                                <ul class="property-feature">
                                    <li>
                                        <span class="area"><img src="{% static 'base/assets/images/icons/area.png' %}" alt="">550 SqFt</span>
                                    </li>
                                    <li>
                                        <span class="bed"><img src="{% static 'base/assets/images/icons/bed.png' %}" alt="">6</span>
                                    </li>
                                    <li>
                                        <span class="bath"><img src="{% static 'base/assets/images/icons/bath.png' %}" alt="">4</span>
                                    </li>
                                    <li>
                                        <span class="parking"><img src="{% static 'base/assets/images/icons/parking.png' %}" alt="">3</span>
                                    </li>
                                </ul>
                            </div>
                            <div class="content">
                                <div class="left">
                                    <h3 class="title"><a href="single-properties.html">{{ listing.listing_title }}</a></h3>
                                    <span class="location"><img src="{% static 'base/assets/images/icons/marker.png' %}" alt="">{{ listing.city }}</span>
                                </div>
                                <div class="right">
                                    <div class="type-wrap">
                                        <span class="price">$550<span>M</span></span>
                                        <span class="type">For Rent</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--Listing end-->
                {% elif listing.listing_type == 'B' %}
                    <!--Listing start-->
                    <div class="property-item col-lg-3 col-md-6 col-12 mb-40">
                        <div class="property-inner">
                            <div class="image">
                                <a href="single-properties.html"><img src="{% static 'base/assets/images/property/property-1.jpg' %}" alt=""></a>
                                <ul class="property-feature">
                                    <li>
                                        <span class="area"><img src="{% static 'base/assets/images/icons/area.png' %}" alt="">550 SqFt</span>
                                    </li>
                                    <li>
                                        <span class="bed"><img src="{% static 'base/assets/images/icons/bed.png' %}" alt="">6</span>
                                    </li>
                                    <li>
                                        <span class="bath"><img src="{% static 'base/assets/images/icons/bath.png' %}" alt="">4</span>
                                    </li>
                                    <li>
                                        <span class="parking"><img src="{% static 'base/assets/images/icons/parking.png' %}" alt="">3</span>
                                    </li>
                                </ul>
                            </div>
                            <div class="content">
                                <div class="left">
                                    <h3 class="title"><a href="single-properties.html">{{ listing.listing_title }}</a></h3>
                                    <span class="location"><img src="{% static 'base/assets/images/icons/marker.png' %}" alt="">{{ listing.city }}</span>
                                </div>
                                <div class="right">
                                    <div class="type-wrap">
                                        <span class="price">$550<span>M</span></span>
                                        <span class="type">For Rent</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--Listing end-->
                {% elif listing.listing_type == 'E' %}
                    <!--Listing start-->
                    <div class="property-item col-lg-3 col-md-6 col-12 mb-40">
                        <div class="property-inner">
                            <div class="image">
                                <a href="single-properties.html"><img src="{% static 'base/assets/images/property/property-1.jpg' %}" alt=""></a>
                                <ul class="property-feature">
                                    <li>
                                        <span class="area"><img src="{% static 'base/assets/images/icons/area.png' %}" alt="">550 SqFt</span>
                                    </li>
                                    <li>
                                        <span class="bed"><img src="{% static 'base/assets/images/icons/bed.png' %}" alt="">6</span>
                                    </li>
                                    <li>
                                        <span class="bath"><img src="{% static 'base/assets/images/icons/bath.png' %}" alt="">4</span>
                                    </li>
                                    <li>
                                        <span class="parking"><img src="{% static 'base/assets/images/icons/parking.png' %}" alt="">3</span>
                                    </li>
                                </ul>
                            </div>
                            <div class="content">
                                <div class="left">
                                    <h3 class="title"><a href="single-properties.html">{{ listing.listing_title }}</a></h3>
                                    <span class="location"><img src="{% static 'base/assets/images/icons/marker.png' %}" alt="">{{ listing.city }}</span>
                                </div>
                                <div class="right">
                                    <div class="type-wrap">
                                        <span class="price">$550<span>M</span></span>
                                        <span class="type">For Rent</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!--Listing end-->
                {% endif %}
            {% endfor %}

        </div>

    </div>
</div>
<!--Featured listings section end-->

为此,Listing可以是PropertyVehicleBusinessEvent。每个Listing都有几个图像,但是对于这种情况,我只希望传递从数据库中首先检索到的单个图像。

我的主要问题是在上下文部分。我只能从模板中获取Listing实例并获取其他模型的其他详细信息,但是从研究中发现,不建议在Django中进行实践。因此,如何获取ListingPropertyVehicleBusiness的详细信息,并获取Event并将其传递给通过字典的模板让我感到非常困惑。

我尝试使用显示的代码,但是在合并来自single imagePropertyVehicleBusiness的其他数据时遇到了麻烦图片。

1 个答案:

答案 0 :(得分:0)

根据@Higor的建议,这就是我对view.py所做的:

context = {
    'listings': Listing.objects.filter(status=True).order_by('-created_at').prefetch_related("listingimages_set")
}
return render(request, 'base/index.html', context)

然后在模板中,我通过以下方式继续访问详细信息:

{% for listing in listings %}
    {% if listing.listing_type == 'P' %}
        {{ listing.listingimages_set.first.image_url.url }} #accessing a single image
        {{ listing.listing_title }}
        {{ listing.property.land_size }}
    {% elif listing.listing_type == 'V' %}
        ....
    {% elif listing.listing_type == 'B' %}
        ....
    {% endif %}
{% endfor %}

这更加整洁了,在访问图像列表时使用first可以为我节省很多时间。