Reputation: 1926
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?
Upvotes: 1
Views: 1514
Reputation: 239290
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.
Upvotes: 1