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

Вернуться на верх