我的问题是关于创建一个 QuerySet Mixin,它为模型和相关模型提供相同的 QuerySet 方法。这是示例代码,第一类ByPositionMixin
是我关注的:
from django.db import models
from django.db.models.query import QuerySet
from django.core.exceptions import FieldError
class ByPositionMixin(object):
def batters(self):
try:
return self.exclude(positions=1)
except FieldError:
return self.exclude(position=1)
class PlayerQuerySet(QuerySet, ByPositionMixin):
pass
class PlayerPositionQuerySet(QuerySet, ByPositionMixin):
pass
class PlayerManager(models.Manager):
def get_query_set(self):
return PlayerQuerySet(self.model, using=self._db)
class PlayerPositionManager(models.Manager):
def get_query_set(self):
return PlayerPositionQuerySet(self.model, using=self._db)
class Position(models.Model):
# pos_list in order ('P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF')
# pos id / pk correspond to index value of pos_list(pos)
pos = models.CharField(max_length=2)
class Player(models.Model):
name = models.CharField(max_length=100)
positions = models.ManyToManyField(Position, through='PlayerPosition')
objects = PlayerManager()
class PlayerPosition(models.Model):
player = models.ForeignKey(Player)
position = models.ForeignKey(Position)
primary = models.BooleanField()
objects = PlayerPositionManager()
在内部ByPositionMixin
,我尝试exclude(positions=1)
针对哪些查询PlayerQuerySet
,如果生成一个FieldError
,我尝试exclude(position=1)
针对哪些查询PlayerPositionQuerySet
。字段名称的区别是精确的,aPlayer()
有位置,但 aPlayerPosition()
只有一个位置。所以exclude()
查询的区别是“职位”/“职位”。由于我将有许多自定义查询(例如batters()
,pitchers()
等),我是否必须为每个查询by_position()
写出try
/代码?except
或者是否有一种不同的方法可以让我编写自定义查询而不必尝试针对一个模型然后针对另一个模型?
更新:基本上,我决定编写一个 kwarg 辅助函数,它为Player
和提供正确的 kwargs PlayerPosition
。它有点复杂(也许完全没有必要),但应该能够简化几个自定义查询的代码。
class ByPositionMixin(object):
def pkw(self, **kwargs):
# returns appropriate kwargs, at the moment, only handles one kwarg
key = kwargs.keys()[0] # e.g. 'positions__in'
value = kwargs[key]
key_args = key.split('__')
if self.model.__name__ == 'Player':
first_arg = 'positions'
elif self.model.__name__ == 'PlayerPosition':
first_arg = 'position'
else:
first_arg = key_args[0]
key = '__'.join([first_arg] + key_args[1:])
return {key: value}
def batters(self): # shows how pkw() is used
return self.exclude(**self.pkw(positions=1))