使用参数创建django管理器

时间:2016-08-25 13:01:09

标签: django django-managers

我有以下情况
我有一个管理器类,根据字段过滤查询集。问题是字段名称根据类不同,但它过滤的值来自同一个地方(所以我认为我不需要几个管理器)。这就是我到目前为止所做的。

class MyManager(models.Manager):
    def __init__(self, field_name):
        super(MyManager, self).__init__()
        self.field_name = field_name

    def get_queryset(self):
        # getting some value
        kwargs = { self.field_name: some_value }
        return super(MyManager, self).get_queryset().filter(**kwargs)

class A:
    # some datamembers

    @property
    def children(self):
        return MyUtils.prepare(self.b_set.all())

class B:
    objects = MyManager(field_name='my_field_name')
    a = models.ForeignKey(A, null=False, blank=False)

当我运行测试时,我从DB中检索一个B对象,并尝试读取children属性,我得到以下错误:

self = <django.db.models.fields.related_descriptors.RelatedManager object at 0x7f384d199290>, instance = <A: A object>

    def __init__(self, instance):
>       super(RelatedManager, self).__init__()
E       TypeError: __init__() takes exactly 2 arguments (1 given)

我知道它是因为构造函数参数,因为当我删除它(或给它一个默认值)时,所有测试都有效。
我怎么能克服这个?这是实现这一目标的正确方法吗? 技术资料:

  1. Django 1.9.5
  2. 测试框架py.test 2.9.1
  3. 由于

2 个答案:

答案 0 :(得分:2)

正如您所看到的,该错误正在发生,因为Django会在您进行相关对象调用时实例化一个新的Manager;该实例化不会获得额外的参数。

您可以尝试将其作为模型的属性,然后通过self.model引用它,而不是以这种方式获取值。

class MyManager(models.Manager):
    def get_queryset(self):
        # getting some value
        kwargs = { self.model.manager_field_name: some_value }

class B:
    manager_field_name = 'my_field_name'
    objects = MyManager()

答案 1 :(得分:2)

另一种选择是动态生成Manager类,例如:

def manager_factory(custom_field):

    class MyManager(models.Manager):
        my_field = custom_field

        def get_queryset(self):
            # getting some value
            kwargs = {self.my_field: 'some-value'}
            return super(MyManager, self).get_queryset().filter(**kwargs)

    return MyManager()


class MyModel(models.Model):
    objects = manager_factory('custom_field')

这样您就可以将Manager与Model类分离。