Django 多对多过滤器

发布于 2025-01-01 07:49:56 字数 2381 浏览 3 评论 0原文

我有一个区域基础设施建模如下:每个区域都有一个ManyToMany国家,并且可以选择说明(如果它是美国境内的一个区域)

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 字段的子字段进行过滤?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

昔日梦未散 2025-01-08 07:49:56

首先,如果您只想要单个项目,为什么要使用 .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 是具有模型 Country 的 M2M。两者具有可比性,这就是您的查询集返回空的原因。

UserProfile.country 设为 Country 的外键,然后您就可以开始工作了。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文