2012-02-02 164 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的外鍵,而您正在營業。