我有这个经理:
class ConfigValueManager(models.Manager):
def get(self, key):
config_value = self.filter(key=key).first()
if config_value:
type_caster = locate(config_value.type)
return type_caster(config_value.value)
return config_value
def set(self, key, value):
self.filter(key=key).update(value=value)
def set2(self, key, value):
qs = self.filter(key=key)
if qs:
qs.update(value=value, type=type(value).__name__, company=self.instance)
else:
self.create(key=key, value=value, type=type(value).__name__, company=self.instance)
问题是我无法覆盖set
。即使我已经在孩子上创建了set
,该方法仍然来自父级。有趣的是get
和set2
很好。即使是add
,在我的示例中也不能被覆盖。
我的问题是如何覆盖set
以及为什么会发生这种情况?
答案 0 :(得分:0)
from django.db import models
from django.db.models.query import QuerySet
class PersonQuerySet(QuerySet):
def set(self, slug, **kwargs):
return self.filter(slug=slug).update(**kwargs)
class Person(models.Model):
name = models.CharField(max_length=100, null=True)
slug = models.CharField(max_length=10, null=True)
objects = PersonQuerySet.as_manager()
from django.test import TestCase
from core.models import Person
class TestSet(TestCase):
def test_just_update_records_with_the_same_slug(self):
Person.objects.create(slug='batman', name='John')
Person.objects.create(slug='batman', name='Connor')
Person.objects.create(slug='bruce', name='Ill be back')
Person.objects.set('batman', name='###')
expected_value = 2
result = Person.objects.filter(name='###').count()
self.assertEqual(result, expected_value)
答案 1 :(得分:0)
我添加了一些为什么不容易实现的细节,因为我在同一问题上苦苦挣扎。
正如我们在django source code中看到的那样,set
(如add
或create
)在动态创建的RelatedManager
中被覆盖。该RelatedManager
实际上将我们的经理用作super class,这就是可以使用您的get
和set2
方法的原因,但对于覆盖的方法却无济于事。
此管理器是在ReverseManyToOneDescriptor.related_manager_cls
缓存的属性中创建的。在您的github片段上的示例中,Company.config_values
是此ReverseManyToOneDescriptor
的实例。
我将通过对您的代码进行一些假设来展示一个有关如何覆盖set
方法的示例,因为它缺少某些定义(例如Company
模型,ForeignKey
FooConfigValue
内的字段。)
我不建议使用它,因为它对django更改绝对不可靠,并且我也没有做任何测试,它只是证明如何创建RelatedManager
实例
在示例代码的末尾添加它,它应该可以工作
def modify_related_manager_set(model_cls):
# model_cls = Company here, and config_values is the related field name
reverse_descriptor = model_cls.config_values
base_set = reverse_descriptor.related_manager_cls.set
def custom_set(*args, **kwargs):
print("in my custom set")
return base_set(*args, **kwargs)
reverse_descriptor.related_manager_cls.set = custom_set
# do this call after all the models have been created
# e.g. after defining FooConfigValue
modify_related_manager_set(Company)
现在您应该看到in my custom set
正在打印。
我知道这没有多大帮助,但至少可以帮助您了解相关字段的工作方式