【问题标题】:Django Order QuerySet by Min Value from Child TableDjango Order QuerySet by Min Value from Child Table
【发布时间】:2021-02-10 16:34:15
【问题描述】:

我正在尝试在 Django 中创建一个我正在努力解决的特定复杂查询。 我正在使用pagination 在索引页面上显示蛋糕列表。我想按不同的属性对它们进行排序。下面是我的索引页面的截图。

Name (A-Z)Name (Z-A) 是通过简单地按“名称”或“-名称”排序 Cake 查询集来实现的,我从页面顶部的表单作为 POST 获得。

cakes_list = Cake.objects.all().order_by('name')

但是,我正在努力按最低价格订购查询集。 每个蛋糕都有不同的尺寸,有不同的价格(蛋糕之间的尺寸和价格不同)。这些存储在Dimension 中,外键指向它们所属的Cake。 我想找出每个蛋糕最便宜的选择,并根据它订购我在分页中使用的蛋糕列表(最低价格升序和降序)。

我还创建了一个方法from_price,它返回那个蛋糕的价格。我在模板中使用它来显示每个蛋糕名称以及最低价格。但我似乎无法在我的排序中实现这一点。

感谢有关如何创建查询或类似查询的帮助,以便我根据每个蛋糕的最低价格对所有蛋糕进行排序。我只是在学习 Django,所以我目前的实现可能并不理想。

保险库/models.py:

class Cake(models.Model):
    name = models.CharField(max_length=200)

    def from_price(self):
        temp = self.dimension_set.aggregate(Min('price')).get('price__min')
        if not temp:
            temp = 0
        return temp

class Dimension(models.Model):
    cake = models.ForeignKey(Cake, on_delete=models.CASCADE)
    dimension = models.CharField(max_length=50)
    price = models.DecimalField(max_digits=6, decimal_places=2)

保险库/views.py

def index(request):
    #from the form on the index page
    order_by = request.POST.get('order_by')
    if not order_by:
        order_by = 'name'

    cakes_list = Cake.objects.all().order_by(order_by)
    paginator = Paginator(cakes_list, 5)

    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)
    return render(request, 'vault/index.html', {'page_obj': page_obj, 'order_by': order_by})


保险库/模板/保险库/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{# Form for cake sorting dropdown #}
<form action="{% url 'vault:index' %}" method="post">
    {% csrf_token %}
    <label for="order_by">Order by:</label>
    <select name="order_by" id="order_by">
        <option {% if order_by == "name" %} selected="selected" {% endif %} value="name">Name (A-Z)</option>
        <option {% if order_by == "-name" %} selected="selected" {% endif %} value="-name">Name (Z-A)</option>
        {% comment %}
        New options for ordering by price
        <option {% if order_by == "" %} selected="selected" {% endif %} value="name">Price from (Low to High)</option>
        <option {% if order_by == "" %} selected="selected" {% endif %} value="-name">Price from (High to Low)</option>
        {% endcomment %}
    </select>
    <input type="submit" value="Select">
</form>

{# Code for printing the list of cakes #}
{% if page_obj %}
    <ul>
        {% for cake in page_obj %}
            <li>
                <a href="{% url 'vault:detail' cake.id %}">
                    {{ cake.name }}
                    {% if cake.from_price %}
                        - from &#163;{{ cake.from_price|floatformat:'2' }}
                    {% endif %}
                </a>
            </li>
        {% endfor %}
    </ul>
{% else %}
    <p>No cakes are available</p>
{% endif %}

{# Code for the pagination navigation elements #}
<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; first</a>
            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}
        <span class="current">
            Page {{  page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">next</a>
            <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
        {% endif %}
    </span>

</div>
</body>
</html>

【问题讨论】:

  • 我不清楚,一个Cake 可以有超过1 个维度的对象(不同的维度和价格)吗?因为你的模型允许它
  • @SergeyPugach 是的,这正是我想做的。我的巧克力蛋糕可能有不同大小的方形和圆形,因此每个维度在维度表中都有自己的条目以及相关的价格。

标签: python django django-queryset one-to-many


【解决方案1】:

在订购之前尝试使用注释:

cakes_list = Cake.objects.annotate(
    max_price=Max('dimension__price'),
).order_by('max_price')

【讨论】:

    【解决方案2】:

    如果您需要每个Cake 记录的最低价格值,那么最简单的方法可能是使用subquery

    from django.db.models import OuterRef, Subquery
    
    sub_q = Dimension.objects.filter(cake=OuterRef('id')).order_by('price')
    qs = Cake.objects.annotate(min_price=Subquery(sub_q.values('prize')[:1]).order_by('min_price')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多