【发布时间】:2016-10-13 12:36:30
【问题描述】:
我有两个模型:City,及其别名 CityAlias。 CityAlias 模型包含City 中的所有名称,以及别名。我想要的是,每当name 搜索City 时,都应该查询CityAlias 模型。这是我想出的:
class CityQuerySet(models.QuerySet):
""" If City is searched by name, search it in CityAlias """
def _search_name_in_alias(self, args, kwargs):
for q in args:
if not isinstance(q, models.Q): continue
for i, child in enumerate(q.children):
# q.children is a list of tuples of queries:
# [('name__iexact', 'calcutta'), ('state__icontains', 'bengal')]
if child[0].startswith('name'):
q.children[i] = ('aliases__%s' % child[0], child[1])
for filter_name in kwargs:
if filter_name.startswith('name'):
kwargs['aliases__%s' % filter_name] = kwargs.pop(filter_name)
def _filter_or_exclude(self, negate, *args, **kwargs):
# handles 'get', 'filter' and 'exclude' methods
self._search_name_in_alias(args=args, kwargs=kwargs)
return super(CityQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)
class City(models.Model):
name = models.CharField(max_length=255, db_index=True)
state = models.ForeignKey(State, related_name='cities')
objects = CityQuerySet.as_manager()
class CityAlias(models.Model):
name = models.CharField(max_length=255, db_index=True)
city = models.ForeignKey(City, related_name='aliases')
示例:Kolkata 将在 City 模型中有一个条目,在 CityAlias 模型中有两个条目:Kolkata 和 Calcutta。上面的QuerySet 允许在name 字段上使用查找。
所以以下两个查询将返回相同的条目:
City.objects.get(name='Kolkata') # <City: Kolkata>
City.objects.get(name__iexact='calcutta') # <City: Kolkata>
到目前为止一切顺利。但是当City 在其他模型中是ForeignKey 时,问题就出现了:
class Trip(models.Model):
destination = models.ForeignKey(City)
# some other fields....
Trip.objects.filter(destination__name='Kolkata').count() # some non-zero number
Trip.objects.filter(destination__name='Calcutta').count() # always returns zero
Django 在内部以不同的方式处理这些连接,并且不调用City 的经理的get_queryset 方法。另一种方法是调用上述查询,如下所示:
Trip.objects.filter(destination=City.objects.get(name='Calcutta'))
我的问题是我可以做点什么吗,以便City 模型被name 搜索,它总是在CityAlias 表中搜索?
还是有其他更好的方法来实现我需要的功能?
【问题讨论】:
-
您的问题是否过于复杂?你可以简单地让 Trip.destination 成为 cityalias 的外键吗?
-
City模型也会有其他字段(如地理位置)。所以这意味着在按名称过滤时使用CityAlias,在应用其他过滤器时使用City。 -
试过这个:Trip.objects.filter(destination__aliases__name='Calcutta').count()
标签: python django django-models