2016-08-22 3 views
0

У меня есть модель страны и модель людей в отпуске в течение определенного года в стране. Я хочу иметь Апи стран, в которых я могу отфильтровать только те страны, в которых некоторые люди имели отпуск в течение определенного года.django rest frame filter на родственной модели

Models.py

from django.db import models 

class Country(models.Model): 
    id = models.CharField(max_length=50,primary_key=True) 
    country = models.CharField(max_length=255,null=True) 

class PersonYear(models.Model): 
    id = models.IntegerField(primary_key=True) 
    person = models.CharField(max_length=255,null=True) 
    year = models.IntegerField(null=True) 
    country = models.ForeignKey(Country, related_name='personyears') 

Содержание модели Страна

id|country 
1|France 
2|Italy 
3|Spain 

Содержание модели PersonYear

id|person|year|country_id 
1|John|2014|1 
2|John|2015|1 
3|Mary|2014|1 

serializers.py

from apiapp.models import PersonYear,Country 
from rest_framework import serializers 

class PersonyearSerializer(serializers.HyperlinkedModelSerializer): 

    class Meta: 
     model = PersonYear 
     fields = ('id','person','year') 

class CountrySerializer(serializers.HyperlinkedModelSerializer): 
    personyears = PersonyearSerializer(many=True) 

    class Meta: 
     model = Country 
     fields = ('id','country','personyears') 

Views.py

import rest_framework_filters as filters 

class PersonyearFilter(filters.FilterSet): 
    id = filters.AllLookupsFilter(name='id') 
    person = filters.AllLookupsFilter(name='person') 
    year = filters.AllLookupsFilter(name='year') 

    class Meta: 
     model = PersonYear 

class PersonyearViewSet(viewsets.ModelViewSet): 
    queryset = PersonYear.objects.all() 
    serializer_class = PersonyearSerializer 
    filter_backends = (filters.backends.DjangoFilterBackend,) 
    filter_fields = ['id','person','year'] 
    filter_class = PersonyearFilter 

class CountryFilter(filters.FilterSet): 
    id = filters.AllLookupsFilter(name='id') 
    nm = filters.AllLookupsFilter(name='country') 
    personyears = filters.RelatedFilter(PersonyearFilter,name='personyears') 

    class Meta: 
     model = Country 

class CountryViewSet(viewsets.ModelViewSet): 
    queryset = Country.objects.all() 
    serializer_class = CountrySerializer 
    filter_backends = (filters.backends.DjangoFilterBackend,) 
    filter_fields = ['id','country','personyears'] 
    filter_class = CountryFilter 

Я хочу, чтобы выбор всех стран, в которых Джон был праздник в 2014 году:

http://localhost:8000/country/?personyears__person=John&personyears__year=2014

я ожидал получить одну запись:

{"id": "1", "country": "France", 
    "personyears": [ 
    { "id": 1, 
     "person": "John" 
     "year": 2014 
    } 
] 
} 

Но вместо этого я повторил эту запись 4 раза. Можете ли вы объяснить, что я делаю неправильно, и как получить то, что я хочу.

Update1:

Я не хочу, только специальное решение для Джона в 2014. Я хочу, чтобы решение для всех случаев Anyperson в AnyYear. Например, я также хочу следующий фильтр, чтобы дать мне один результат: http://localhost:8001/api/country/?personyears__person=Mary&personyears__year=2014

UPDATE2:

Я попытался заменить:

queryset = Country.objects.all() 

по:

queryset = Country.objects.all().distinct() 

Это помогло получить ожидаемый результат (1 запись):

локальный: 8000/страна/personyears__person = Джон & personyears__year = 2014

Но теперь я получаю неожиданный/нежелательный результат для человека = 'Мэри'/год = '2015'

локальный: 8000/страна /? personyears__person = Mary & personyears__year = 2015

Я не ожидал результата (Мария не отправилась в отпуск в 2015 году в любую страну). Но я получил

{"id": "1","country": "France", 
    "personyears": [ 
      { 
       "id": 1, 
       "person": "John", 
       "year": 2014 
      }, 
      { 
       "id": 2, 
       "person": "John", 
       "year": 2015 
      }, 
      { 
       "id": 3, 
       "person": "Mary", 
       "year": 2014 
      } 
    ] 
    } 
+0

Итак, как часто был Джон во Франции в 2014 году? Кажется, что в последнем запросе отсутствует '.distinct()'. – dhke

+0

Это действительно похоже на замену 'queryset = Country.objects.all()' в CountryViewSet на 'queryset = Country.objects.all(). Distinct()' просто делает трюк. Но сделаем еще несколько тестов. – waterbug

+0

Ну, это не сработало. Если я теперь фильтрую на человека = Мэри и год = 2015, результаты скажут мне, что Мэри отправилась во Францию ​​в 2015 году, в то время как она не ушла нигде в 2015 году. – waterbug

ответ

1

Ваш queryset должен быть:

Country.objects.filter(personyears__year='your_year', person='your_person').values_list('country', flat=True) 

Это будет возвращать список всех стран.

Примечание: Это будет фильтровать на основе имени человека, которое может быть одинаковым для разных пользователей. Должна быть еще одна модель: Person, чья foreign key должна быть отображена на PersonYear.

+0

занят занятым занятым b .. – waterbug

+0

Итак, я заменил запрос в CountryViewSet на ' queryset = Country.objects.filter (personyears__year = '2014', personyears__person = 'John'). values_list ('country', flat = True) 'Я тестировал его сначала в оболочке, в которой он работал. Но в views.py он дает ошибку 'AttributeError: Got AttributeError при попытке получить значение для поля 'id' в сериализаторе 'CountrySerializer'. Поле сериализатора может быть названо неправильно и не соответствует никакому атрибуту или ключу на экземпляре «unicode». – waterbug

+0

Также попытался заменить это 'queryset = Country.objects.filter (personyears__year = '2014', personyears__person = 'John'). 'который не дает ошибки, но тот же результат (4 идентичных записи). Я также задаюсь вопросом, работает ли ваше предложение, как использовать его в общем виде (например, во всех странах, в которых Мария имела отпуск в 2015 году) – waterbug

Смежные вопросы