Как отфильтровать набор запросов на основе значения другой модели в 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="{% 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
Спасибо тебе за это. Я добавил формы.py и укороченные модели.py. Подскажите, пожалуйста, как лучше узнать возраст? - person MiniGunnR; 23.07.2015
comment
В вашей форме вы запрашиваете возраст, но в вашей модели у вас есть день рождения, вам нужно будет рассчитать возраст от дня рождения или добавить поле возраста в вашу модель. - person Gocht; 23.07.2015
comment
Если я добавлю поле возраста, оно не будет увеличиваться на 1 в год. Поэтому я использовал дату рождения. Я думаю, что лучше вычислять возраст по дате рождения. - 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(). Спасибо чувак. Смешной. - 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