Фильтр Django ManyToMany - PullRequest
       6

Фильтр Django ManyToMany

1 голос
/ 02 февраля 2012

У меня есть инфраструктура региона, смоделированная следующим образом: в каждом регионе имеется множество стран и, при необходимости, указывается (если это регион в США)

from django.contrib.auth.models import User
from django.contrib.localflavor.us.models import USStateField
from django.db import models

from django_countries import CountryField


class CountryManager(models.Manager):
    def get_by_natural_key(self, country):
        return self.get(country=country)


class Country(models.Model):
    country = CountryField(unique=True)

    objects = CountryManager()

    class Meta:
        ordering = ('country',)

    def __unicode__(self):
        return unicode(self.country.name)

    def natural_key(self):
        return (self.country.code,)


class StateManager(models.Manager):
    def get_by_natural_key(self, state):
        return self.get(state=state)


class State(models.Model):
    state = USStateField(unique=True)

    objects = StateManager()

    class Meta:
        ordering = ('state',)

    def __unicode__(self):
        return self.get_state_display()

    def natural_key(self):
        return (self.state,)


class Region(models.Model):
    name = models.CharField(max_length=255, unique=True)
    coordinator = models.ForeignKey(User, null=True, blank=True)
    is_us = models.BooleanField('Is a US region')
    countries = models.ManyToManyField(Country)
    states = models.ManyToManyField(State, blank=True)

    class Meta:
        ordering = ('name',)

    def __unicode__(self):
        return self.name

У каждого пользователя есть профиль, определенный (частично) следующим образом:

class UserProfile(models.Model):

    user = models.OneToOneField(User, related_name='user_profile')
    city = models.CharField(max_length=255)
    country = CountryField()
    state = USStateField(_(u'US only (determines user's region)'), blank=True, null=True)

Я пытаюсь отфильтровать кучу пользовательских объектов по регионам. Итак, у меня есть

        region = Region.objects.filter(id=self.request.GET['filter_region'])
        if len(region) == 0:
            raise Exception("Region not found for filter")
        if len(region) > 1:
            raise Exception("Multiple regions found for filter?")
        region = region[0]

        queryset = queryset.filter(user_profile__country__in=region.countries.all)

К сожалению, это возвращает пустой набор запросов. Я подозреваю, что это связано с тем фактом, что модель "Страна" имеет внутри себя поле "страна" (я знаю, что это ужасно неоднозначное наименование, а не мой код), и я фильтрую только по моделям "Страна", а не поля "страны" внутри них. (Это имеет смысл?)

Как мне выполнить фильтрацию по подполю поля ManyToMany?

1 Ответ

1 голос
/ 02 февраля 2012

Во-первых, почему вы используете .filter(), если вам нужен только один элемент:

region = Region.objects.get(id=self.request.GET['filter_region'])

Это вызовет исключение ObjectDoesNotExist, если объект не существует, но вы вызываете исключение, если набор запросов в любом случае пуст. Если вам нужно поймать это исключение, вы можете использовать блок try...except или get_object_or_404, если вы находитесь в представлении.

Во-вторых, не используйте self.request.GET['filter_region'] напрямую. Если ключ не установлен, вы поднимите IndexError. Используйте вместо:

self.request.GET.get('filter_region')

Теперь, что касается вашей актуальной проблемы: UserProfile.country - это CountryField, который является просто специализированным CharField. Принимая во внимание, что Region.countries является M2M с моделью Country. Они не сопоставимы, поэтому ваш набор запросов возвращается пустым.

Сделайте UserProfile.country внешним ключом для Country, и вы в деле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...