【问题标题】:How to pass queryset data with multiple relationships to a template in Django如何将具有多个关系的查询集数据传递给Django中的模板
【发布时间】:2019-11-10 09:13:26
【问题描述】:

我正在处理具有多个 OneToOneOneToMany 关系的模型的项目。主模型 Listing 有 4 个其他模型引用它,其中一个 OneToOne 模型取决于类型。另一个模型ListingImages 模型与Listing 模型具有OneToMany 关系。因此,我想传递来自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 中不推荐这样做。那么如何获取Listing 详细信息,无论是PropertyVehicleBusiness 还是Event 并获得single image 并通过字典将其传递给模板,这让我感到非常困惑.

我已尝试使用显示的代码,但在合并来自 PropertyVehicleBusinessEvent 的其他数据并获取单个图像时遇到了麻烦。

【问题讨论】:

  • 我可能遗漏了一些东西,但你为什么要这样做?你可以简单地做context = {'listings': listings},就是这样。然后您像在模板上所做的那样遍历该列表。无论是在列表实例中的任何内容,您都可以访问它。
  • @Higor,我将如何使用您的方法从模板中获取图像?
  • 与您在视图中所做的相同,但现在在模板上。 listing.listingimages_set.all 基本上你会看那些
  • 这是在 Django 中正确的做法吗?对大型数据库数据有影响吗?
  • 嗯通过再次阅读您的代码,您在模板上有很多 if/else。你知道你会看到什么类型吗?如果是这样,您可以在此处公开过滤

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


【解决方案1】:

根据@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 为我节省了很多。

【讨论】:

    猜你喜欢
    • 2018-07-10
    • 1970-01-01
    • 2021-01-27
    • 2021-02-25
    • 1970-01-01
    • 2017-07-14
    • 2014-11-04
    • 2018-09-10
    • 2016-11-17
    相关资源
    最近更新 更多