I have a Region infrastructure modeled as follows: Each region has a ManyToMany of countries, and optionally states (if it's a region within the US)

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

Each user has a profile defined (partially) as follows:

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)

I'm trying to filter a bunch of user objects by region. So I have

        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)

Sadly though, this returns an empty queryset. I suspect it has to do with the fact that the "Country" model has a "country" field within it (terrible ambiguous naming, I know, not my code originally), and I'm only filtering by "Country" models, not the "country" fields within them. (Does that make sense?)

How can I filter by a subfield of the ManyToMany field?

有帮助吗?

解决方案

First, why are you using .filter() if you want just a single item do:

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

That will raise an ObjectDoesNotExist exception if the object doesn't exist, but you're raising an exception if the queryset is empty anyways. If you need to catch that exception you can either use a try...except block or get_object_or_404 if you're in a view.

Second, don't use self.request.GET['filter_region'] directly. If the key isn't set you'll raise an IndexError. Use, instead:

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

Now, as to your actual problem: UserProfile.country is a CountryField which is just a specialized CharField. Whereas Region.countries is a M2M with the model Country. The two are not comparable, which is why your queryset is coming back empty.

Make UserProfile.country a foreign key to Country and you're in business.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top