[英]How and why I can't override related manager method on django?
I have this manager:我有这个经理:
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)
the problem is that I can't overwrite set
.问题是我无法覆盖
set
。 The method is still coming from the parent, even though I've created set
on the child.该方法仍然来自父级,即使我已经在子级上创建了
set
。 Funny thing is that get
and set2
are fine.有趣的是
get
和set2
问题。 Even add
which isn't in my example can't be overridden.即使
add
不在我的示例中也不能被覆盖。
My question is how can I overwrite set
and why this happens?我的问题是如何覆盖
set
以及为什么会发生这种情况?
I add some details on why it's not easily possible, because I struggled on the same issue.我添加了一些细节,说明为什么这不容易实现,因为我在同一个问题上苦苦挣扎。
set
, like add
or create
, are overridden in the dynamically created RelatedManager
, as we can see in the django source code . set
和add
或create
一样,在动态创建的RelatedManager
中被覆盖,正如我们在django 源代码中看到的那样。 This RelatedManager
actually uses our manager as a super class that's why your get
and set2
methods can used, but it does not help for overridden methods.这个
RelatedManager
实际上将我们的管理器用作超类,这就是可以使用get
和set2
方法的原因,但它对重写方法没有帮助。
This manager is created in the ReverseManyToOneDescriptor.related_manager_cls
cached property.该管理器在
ReverseManyToOneDescriptor.related_manager_cls
缓存属性中创建。 In the example on your github snippet, Company.config_values
is an instance of this ReverseManyToOneDescriptor
.在您的 github 片段示例中,
Company.config_values
是此ReverseManyToOneDescriptor
的一个实例。
I'll show an example on how to override the set
method, by making some assumptions on your code, because it misses some definitions (like the Company
model, the ForeignKey
field inside FooConfigValue
.)我将通过对您的代码做出一些假设来展示如何覆盖
set
方法的示例,因为它遗漏了一些定义(例如Company
模型, FooConfigValue
中的ForeignKey
字段。)
I don't advise to use it, as it's absolutely not robust against django changes, and I didn't do any test, it just serves as a proof on how RelatedManager
instances are created Add this at the end of the example code and it should work我不建议使用它,因为它对 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)
And you should now see the in my custom set
being printed.你现在应该看到
in my custom set
正在打印。
I know this doesn't help much, but at least it helped understand how related fields work我知道这没什么帮助,但至少有助于理解相关领域的工作原理
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)
https://github.com/luivilella/django-test-manager https://github.com/luivilella/django-test-manager
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.