私の質問は、モデルと関連モデルの両方に同一の QuerySet メソッドを提供する QuerySet Mixin の作成に関するものです。これがサンプルコードで、最初のクラス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
ます。フィールド名の違いは正確で、aには位置がありますが、aには 1 つの位置しかありません。したがって、クエリの違いは「位置」/「位置」です。多くのカスタム クエリ (例: 、など) があるため、それぞれについて書き出す/コードを作成する必要がありますか?FieldError
exclude(position=1)
PlayerPositionQuerySet
Player()
PlayerPosition()
exclude()
batters()
pitchers()
by_position()
try
except
または、あるモデルに対して試行してから別のモデルに対して試行することなく、カスタム クエリを作成できる別のアプローチはありますか?
Player
更新: 基本的に、 と の両方に正しい kwargs を提供する kwarg ヘルパー関数を作成することにしました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))