2012-02-02 117 views
1

我建模为一个地区的基础设施如下:每个地区都有国家的多对多,和可选的状态(如果它是在美国内的区域)Django的多对多过滤

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

首先,你为什么要使用.filter(),如果你想只是一个单一的项目做:

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

这将引发ObjectDoesNotExist异常,如果对象不存在,但如果你抛出一个异常无论如何,queryset是空的。如果您需要捕获该例外情况,则可以使用try...except区块或get_object_or_404,如果您在视图中。第二,请不要直接使用self.request.GET['filter_region']。如果没有设置密钥,则会引发IndexError。使用,而不是:现在

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

,为您的实际问题:UserProfile.countryCountryField这仅仅是一个专门CharField。而Region.countries是一款型号为Country的M2M。这两个是,不是可比,这就是为什么你的queryset回来空了。

使UserProfile.country成为Country的外键,而您正在营业。