Как да филтрирам набор от заявки въз основа на стойност на друг модел в Django?

Опитвам се да направя проста функция за търсене. Използвам модела User и модела UserProfile с връзка OneToOne. Успешно успях да търся по потребителско име, име и фамилия, като и трите полета са в модела User. Искам обаче да филтрирам по полетата, налични в UserProfile модел, напр. пол, възраст, местоположение и др.

views.py

def Home(request):
    query = request.GET.get('query', '')
    queryset = User.objects.none()
    if request.method == "GET":
        form = SearchForm(request.GET)
        if form.is_valid():
            if query != '':
                queryset = User.objects.filter(Q(username__icontains=query)
                                             | Q(first_name__icontains=query)
                                             | Q(last_name__icontains=query)).exclude(is_staff=True)
    else:
        form = SearchForm()
    return render(request, "main/home.html", {'form': form, 'queryset': queryset})

home.html

{% extends "base.html" %}

{% block body %}
    <h3>Home</h3>
    <p>
    <form method="get" action="">
        {{ form.as_p }}

        <input type="submit" value="Search"/>
    </form>
    </p>

    <p>
    {% for user in queryset %}
        <a href="/bg{% url 'main:profile' user.id %}">{{ user.get_full_name }}</a> <br/>
    {% endfor %}
    </p>
{% endblock %}

forms.py

class SearchForm(forms.Form):
    query = forms.CharField(max_length=100, label="", widget=forms.TextInput(attrs={'placeholder': 'Search...'}), required=False)
    age_from = forms.IntegerField(label="", widget=forms.NumberInput(attrs={'placeholder': 'Age from'}), required=False)
    age_to = forms.IntegerField(label="", widget=forms.NumberInput(attrs={'placeholder': 'Age to'}), required=False)

models.py

UserProfile(models.Model):
    sex_choices = (
        ('Male', 'Male'),
        ('Female', 'Female'),
        ('Other', 'Other'),
    )
    sex = models.CharField(max_length=6,
                           choices=sex_choices,
                           default='Male')
    birth_date = models.DateField()

Как мога да включа опции за търсене въз основа на други полета на модел UserProfile, който има връзка OneToOne с модел User?


person MiniGunnR    schedule 23.07.2015    source източник
comment
Мисля, че трябва да публикувате вашите модели.   -  person Gocht    schedule 23.07.2015
comment
@Gocht Добавен модел, както и формуляри.   -  person MiniGunnR    schedule 23.07.2015


Отговори (1)


Трябва да използвате свързаното име.

Тъй като не сте споделили дефиницията на вашите модели, да предположим:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    sex = models.CharField(...)
    ...

И така, когато питате:

User.objects.filter(user_profile_set__sex='female')

РЕДАКТИРАНЕ

За да направите заявка въз основа на възраст, като се има предвид, че питате за „възраст“ във вашия формуляр и съхранявате рождена дата във вашия модел, можете да опитате нещо подобно:

from datetime import datetime
age = 18  # this shoudl come from form
birth_year = datetime.now().year - age
User.objects.filter(user_profile_set__birth_date__year=birth_year)
person Gocht    schedule 23.07.2015
comment
Благодаря ви за това. Добавих forms.py и съкратения models.py. Можете ли да ми кажете кой е най-добрият начин за запитване за възрастта? - person MiniGunnR; 23.07.2015
comment
Във вашия формуляр вие питате за възраст, но във вашия модел имате ден на раждане, ще трябва да изчислите възрастта от деня на раждане или да добавите поле за възраст във вашия модел. - person Gocht; 23.07.2015
comment
Ако добавя поле за възраст, то няма да се увеличава с 1 на година. Така че използвах birth_date. Мисля, че е по-добре да се изчисли възрастта от birth_date. - person MiniGunnR; 23.07.2015
comment
unsupported operand type(s) for -: 'int' and 'unicode' Опитах се да използвам int() за конвертиране в цяло число или u' за конвертиране в unicode. Не става. Когато го пресъздам в обвивката на Python User.objects.filter(user_profile_set__birth_date__year=birth_year) ‹- това работи, но User.objects.filter(user_profile_set__birth_date__year__gte=birth_year) ‹- това не работи, казвайки Unsupported lookup 'year_gte' for DateField or join on the field not permitted. - person MiniGunnR; 23.07.2015
comment
Обратното проследяване подчертава този ред birth_year = datetime.now().year - age - person MiniGunnR; 23.07.2015
comment
Моля, използвайте някоя онлайн услуга, за да получите пълното проследяване, не мисля, че този ред хвърля изключение. - person Gocht; 23.07.2015
comment
age_from е уникод във вашия код приятелю, конвертирайте го в int -› int(age_from) - person Gocht; 23.07.2015
comment
Можех да се закълна, че бях опитал да конвертирам това в int(). Мерси човече. LoL. - person MiniGunnR; 23.07.2015
comment
Също така, можете ли да ми кажете за това Unsupported lookup 'year_gte' for DateField or join on the field not permitted. всеки път, когато се опитам да използвам __gte или __lte в моята заявка? Обратно проследяване: dpaste.com/0MV1D7X - person MiniGunnR; 23.07.2015
comment
Добре, изчакайте, ако конвертирам възрастта в низ и я запиша във формата за дата, той изчислява без грешка. Просто трябва да разбера как да го направя ефективно. Не се занимавай с това. :) - person MiniGunnR; 23.07.2015
comment
@MiniGunnR Изглежда, че не е възможно (освен ако не е по лесен начин), но можете да направите нещо подобно User.objects.filter(user_profile_set__birth_day__gte=date(age_from, 1, 1)) - person Gocht; 23.07.2015
comment
Това работи filter(profile__birth_date__lte = str(birth_year_from) + '-' + str(now.month) + '-' + str(now.day)). Свързаното име се промени на profile между другото. - person MiniGunnR; 23.07.2015
comment
Намерихте своето уравнение. Радвам се да помогна - person Gocht; 23.07.2015