Django:为模型和相关模型构建QuerySet Mixin

时间:2013-10-16 17:36:13

标签: django django-models

我的问题是创建一个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 }。字段名称的差异是准确的,Player()有位置,但PlayerPosition()只有一个位置。因此,exclude()查询的不同之处在于“位置”/“位置”。由于我将有许多自定义查询(例如batters()pitchers()by_position()等),我是否必须为每个查询写出try / except代码一个?

或者是否有一种不同的方法可以让我编写自定义查询而不必尝试反对一个模型然后反对另一个模型?

更新:基本上,我已经决定编写一个kwarg辅助函数,它为PlayerPlayerPosition提供了正确的kwargs。它有点复杂(也许完全没必要),但应该能够简化几个自定义查询的代码。

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))

0 个答案:

没有答案