Django Order QuerySet by Min Value from Child Table
Django Order QuerySet by Min Value from Child Table
我正尝试在 Django 中创建一个我正在努力解决的特定复杂查询。
我正在使用 pagination 在索引页上显示蛋糕列表。我想按不同的属性对它们进行排序。下面是我的索引页面的截图。
Name (A-Z)
& Name (Z-A)
是通过简单地按 'name' 或 '-name' 对 Cake 查询集进行排序来实现的,我从页面顶部。
cakes_list = Cake.objects.all().order_by('name')
但是我很难按最低价格订购查询集。
每个蛋糕都有不同的尺寸,价格也不同(蛋糕之间的尺寸和价格不同)。这些存储在 Dimension
中,外键指向它们所属的 Cake
。
我想找出每个蛋糕最便宜的选择,并根据它(最低价格升序和降序)订购我在分页中使用的蛋糕列表。
我还创建了一个方法 from_price
,其中 returns 那个蛋糕的价格。我在我的模板中使用它来显示每个蛋糕的名称和最低价格。但我似乎无法将其应用到我的排序中。
感谢您帮助我创建查询或类似查询,让我可以根据每个蛋糕的最低价格对我的所有蛋糕进行排序。我刚刚开始学习 Django,所以我目前的实现可能并不理想。
vault/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)
vault/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})
vault/templates/vault/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 £{{ 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">« 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 »</a>
{% endif %}
</span>
</div>
</body>
</html>
尝试在订购之前使用注释:
cakes_list = Cake.objects.annotate(
max_price=Max('dimension__price'),
).order_by('max_price')
如果您需要每个 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')
我正尝试在 Django 中创建一个我正在努力解决的特定复杂查询。 我正在使用 pagination 在索引页上显示蛋糕列表。我想按不同的属性对它们进行排序。下面是我的索引页面的截图。
Name (A-Z)
& Name (Z-A)
是通过简单地按 'name' 或 '-name' 对 Cake 查询集进行排序来实现的,我从页面顶部。
cakes_list = Cake.objects.all().order_by('name')
但是我很难按最低价格订购查询集。
每个蛋糕都有不同的尺寸,价格也不同(蛋糕之间的尺寸和价格不同)。这些存储在 Dimension
中,外键指向它们所属的 Cake
。
我想找出每个蛋糕最便宜的选择,并根据它(最低价格升序和降序)订购我在分页中使用的蛋糕列表。
我还创建了一个方法 from_price
,其中 returns 那个蛋糕的价格。我在我的模板中使用它来显示每个蛋糕的名称和最低价格。但我似乎无法将其应用到我的排序中。
感谢您帮助我创建查询或类似查询,让我可以根据每个蛋糕的最低价格对我的所有蛋糕进行排序。我刚刚开始学习 Django,所以我目前的实现可能并不理想。
vault/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)
vault/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})
vault/templates/vault/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 £{{ 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">« 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 »</a>
{% endif %}
</span>
</div>
</body>
</html>
尝试在订购之前使用注释:
cakes_list = Cake.objects.annotate(
max_price=Max('dimension__price'),
).order_by('max_price')
如果您需要每个 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')