Django сортировка и фильтрация объектов в шаблоне на основе параметров url
Моя проблема заключается в сортировке и фильтрации объектов в шаблоне .html. У меня работают обе функции, но если я использую одну из них, то вторая не работает.
Мой шаблон:
<form action="{% url 'adverts' %}" method="get">
<div class="form_field">
<label for="formInput#search">Search Adverts</label>
<input style="width: 400px;" class="input input--text" id="formInput#search"
type="text" value="{{search_query}}" name="search_query" placeholder="Search by Adverts title, brand or description">
</div>
</form>
<main>
<div class="search">
<h2>Number of adverts: {{num}}</h2>
<form action="{% url 'adverts' %}">
<span>Sort by:</span>
<select name="sort">
<option value="new">newest</option>
<option value="old">older</option>
<option value="price_low">price low</option>
<option value="price_high">price high</option>
<option value="mileage_low">mileage lowest</option>
<option value="mileage_high">mileage higher</option>
<input type="submit" value="Sort">
</select>
</form>
{% for advert in adverts %}
<div class="mainAdvert">
<a href="{% url 'single-advert' advert.id %}">
<div class="row">
<div class="column">
<img src="{{ advert.featured_image.url }}" class="advertImage">
</div>
<div class="column1">
<span class="titleAdvert"><b>{{advert.title}}</b></span>
<ul>
<li class="header">{{advert.year_of_production}}</li>
<li class="header">{{advert.mileage}}km</li>
<li class="header">{{advert.fuel_type}}</li>
<li class="header">{{advert.variant}}</li>
<li class="header">{{advert.created}}</li>
</ul>
<span class="location"><img class="address-icon" src="images/pin.png" alt="" /><b>Adres: </b>Rogowo, Poland</span>
</div>
<div class="column">
<span><h2 class="price">{{advert.price}}PLN</h2></span>
</div>
</div>
</a>
</div>
{% endfor %}
Моя функция views.py:
def adverts(request):
page = 'adverts'
adverts, search_query = searchAdverts(request)
adverts = Advert.objects.all()
sort_by = request.GET.get('sort')
if sort_by == 'new':
adverts = Advert.objects.all().order_by('-created')
elif sort_by == 'old':
adverts = Advert.objects.all().order_by('created')
elif sort_by == 'mileage-high':
adverts = Advert.objects.all().order_by('-mileage')
elif sort_by == 'mileage-low':
adverts = Advert.objects.all().order_by('mileage')
elif sort_by == 'power-high':
adverts = Advert.objects.all().order_by('-power')
elif sort_by == 'power-low':
adverts = Advert.objects.all().order_by('power')
else:
adverts = Advert.objects.all().order_by('-created')
num = len(adverts)
context = {'adverts': adverts, 'num': num, 'page': page, 'search_query': search_query}
return render(request, 'adverts/adverts.html', context)
и моя функция utils.py для поиска:
from .models import Advert, Brand
from django.db.models import Q
def searchAdverts(request):
search_query = ""
if request.GET.get('search_query'):
search_query = request.GET.get('search_query')
brands = Brand.objects.filter(name__icontains=search_query)
adverts = Advert.objects.distinct().filter(
Q(title__icontains=search_query) |
Q(description__icontains=search_query) |
Q(brand__in=brands)
)
return adverts, search_query
Я думаю, что проблема в переменной 'adverts'. Потому что я передаю ее в свой шаблон. И я использую только переменную из сортировки.
adverts = Advert.objects.all()
Я пытался изменить 'adverts' на другое имя для сортировки и передал его в свой шаблон... что-то вроде этого:
{% if ... %}
{% for advert in adverts %}
<div class="mainAdvert">
<a href="{% url 'single-advert' advert.id %}">
<div class="row">
<div class="column">
<img src="{{ advert.featured_image.url }}" class="advertImage">
</div>
<div class="column1">
<span class="titleAdvert"><b>{{advert.title}}</b></span>
<ul>
<li class="header">{{advert.year_of_production}}</li>
<li class="header">{{advert.mileage}}km</li>
<li class="header">{{advert.fuel_type}}</li>
<li class="header">{{advert.variant}}</li>
<li class="header">{{advert.created}}</li>
</ul>
<span class="location"><img class="address-icon" src="images/pin.png" alt="" /><b>Adres: </b>Rogowo, Poland</span>
</div>
<div class="column">
<span><h2 class="price">{{advert.price}}PLN</h2></span>
</div>
</div>
</a>
</div>
{% endfor %}
{% else ... %}
{% for advert in adverts2 %}
<div class="mainAdvert">
<a href="{% url 'single-advert' advert.id %}">
<div class="row">
<div class="column">
<img src="{{ advert.featured_image.url }}" class="advertImage">
</div>
<div class="column1">
<span class="titleAdvert"><b>{{advert.title}}</b></span>
<ul>
<li class="header">{{advert.year_of_production}}</li>
<li class="header">{{advert.mileage}}km</li>
<li class="header">{{advert.fuel_type}}</li>
<li class="header">{{advert.variant}}</li>
<li class="header">{{advert.created}}</li>
</ul>
<span class="location"><img class="address-icon" src="images/pin.png" alt="" /><b>Adres: </b>Rogowo, Poland</span>
</div>
<div class="column">
<span><h2 class="price">{{advert.price}}PLN</h2></span>
</div>
</div>
</a>
</div>
{% endfor %}
{% endif %}
Является ли это хорошей идеей? Или может мне просто нужно изменить функцию mu? Я хочу, например, искать 'audi' и сортировать результаты от самых старых в том же шаблоне.
Ваша функция adverts всегда пишет поверх вашей searchAdverts, поскольку вы присваиваете новый запрос той же переменной.
adverts, search_query = searchAdverts(request)
adverts = Advert.objects.all()
sort_by = request.GET.get('sort')
Здесь вы устанавливаете adverts на отфильтрованный запрос в первой строке, затем сразу же вы устанавливаете adverts на Advert.objects.all(), делая вызов searchAdverts(request) избыточным, шаг первый - перестаньте делать это.
Во-вторых, вы плохо используете ленивые запросы Django. Опять же, вы переназначаете adverts после назначения, что означает, что вы назначаете одну и ту же переменную 3 раза, не используя ее. Когда вы пишете adverts = Advert.objects.all() в Django, вы на самом деле не вызываете этот запрос, вы просто подготавливаете его как таковой, это означает, что вы можете добавить дополнительные фильтры, упорядочивание и т.д. после первоначального присвоения, не делая дополнительных запросов к базе данных, поэтому основная часть ваших объявлений может быть написана следующим образом:
adverts = Advert.objects.all()
sort_by = request.GET.get('sort')
if sort_by == 'new':
adverts = adverts.order_by('-created')
elif sort_by == 'old':
adverts = adverts.order_by('created')
elif sort_by == 'mileage-high':
adverts = adverts.order_by('-mileage')
elif sort_by == 'mileage-low':
adverts = adverts.order_by('mileage')
elif sort_by == 'power-high':
adverts = adverts.order_by('-power')
elif sort_by == 'power-low':
adverts = adverts.order_by('power')
else:
adverts = adverts.order_by('-created')
Это заставляет вашу строку adverts = Advert.objects.all() действительно использоваться и делает ваш код немного чище
Да, это делает код более чистым. Спасибо за помощь. Я сделал очень простое изменение и теперь код моей функции выглядит так:
def adverts(request):
page = 'adverts'
search_query = ""
#searching
if request.GET.get('search_query'):
adverts, search_query = searchAdverts(request)
else:
#sorting
adverts = Advert.objects.all()
sort_by = request.GET.get('sort')
if sort_by == 'new':
adverts = adverts.order_by('-created')
elif sort_by == 'old':
adverts = adverts.order_by('created')
elif sort_by == 'mileage-high':
adverts = adverts.order_by('-mileage')
elif sort_by == 'mileage-low':
adverts = adverts.order_by('mileage')
elif sort_by == 'power-high':
adverts = adverts.order_by('-power')
elif sort_by == 'power-low':
adverts = adverts.order_by('power')
else:
adverts = adverts.order_by('-created')
num = len(adverts)
context = {'adverts': adverts, 'num': num, 'page': page, 'search_query': search_query}
return render(request, 'adverts/adverts.html', context)
И теперь все работает так, как я хотел :D