从 Django 中的基本模型实例返回代理模型实例的正确方法?
假设我有模型:
class Animal(models.Model):
type = models.CharField(max_length=255)
class Dog(Animal):
def make_sound(self):
print "Woof!"
class Meta:
proxy = True
class Cat(Animal):
def make_sound(self):
print "Meow!"
class Meta:
proxy = True
假设我想做:
animals = Animal.objects.all()
for animal in animals:
animal.make_sound()
我想要取回一系列的汪汪声和喵声。显然,我可以在基于 Animal_type 分叉的原始模型中定义 make_sound,但是每次我添加新的动物类型(想象它们位于不同的应用程序中)时,我都必须进入并编辑 make_sound 函数。我宁愿只定义代理模型并让它们自己定义行为。据我所知,无法返回混合的 Cat 或 Dog 实例,但我想也许我可以在返回猫或狗模型的主类上定义一个“get_proxy_model”方法。
当然,您可以这样做,并传递诸如主键之类的内容,然后只需执行 Cat.objects.get(pk = Passed_in_primary_key) 即可。但这意味着对已有的数据进行额外的查询,这似乎是多余的。有什么方法可以有效地将动物变成猫或狗实例吗?实现我想要实现的目标的正确方法是什么?
Say I have models:
class Animal(models.Model):
type = models.CharField(max_length=255)
class Dog(Animal):
def make_sound(self):
print "Woof!"
class Meta:
proxy = True
class Cat(Animal):
def make_sound(self):
print "Meow!"
class Meta:
proxy = True
Let's say I want to do:
animals = Animal.objects.all()
for animal in animals:
animal.make_sound()
I want to get back a series of Woofs and Meows. Clearly, I could just define a make_sound in the original model that forks based on animal_type, but then every time I add a new animal type (imagine they're in different apps), I'd have to go in and edit that make_sound function. I'd rather just define proxy models and have them define the behavior themselves. From what I can tell, there's no way of returning mixed Cat or Dog instances, but I figured maybe I could define a "get_proxy_model" method on the main class that returns a cat or a dog model.
Surely you could do this, and pass something like the primary key and then just do Cat.objects.get(pk = passed_in_primary_key). But that'd mean doing an extra query for data you already have which seems redundant. Is there any way to turn an animal into a cat or a dog instance in an efficient way? What's the right way to do what I want to achieve?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我尝试了很多方法来做到这一点。最后,最简单的似乎就是前进的道路。
覆盖基类的
__init__
。我知道 eval 可能很危险,等等,但是您始终可以在类型选择上添加保护/验证,以确保它是您想要看到的。
除此之外,我想不出任何明显的陷阱,但如果我发现任何陷阱,我会提及它们/删除答案! (是的,我知道这个问题非常老,但希望这能帮助其他遇到同样问题的人)
I played around with a lot of ways to do this. In the end the most simple seems to be the way forward.
Override
__init__
of the base class.I know eval can be dangerous, bla bla bla, but you can always add safeguarding/validation on the type choice to ensure it's what you want to see.
Besdies that, I can't think of any obvious pitfalls but if i find any i'll mention them/ delete the answer! (yeah i know the question is super old, but hopefully this'll help others with the same problem)
您或许可以使用此处描述的方法使 Django 模型具有多态性。我相信该代码处于开发的早期阶段,但值得研究。
You can perhaps make Django models polymorphic using the approach described here. That code is in early stages of development, I believe, but worth investigating.
这个答案可能在某种程度上回避了这个问题,因为它不使用代理模型。然而,正如问题所提出的,它确实让人们编写以下内容(如果添加新类型,则无需更新
Animal
类)——为了避免元类编程,可以使用 组合优于继承。例如,
如果
Dog
和Cat
类需要访问Animal
实例,您还可以调整type_instance()<上面的 /code> 方法将其所需的内容传递给类构造函数(例如
self
)。This answer may be side-stepping the question somewhat because it doesn't use proxy models. However, as the question asks, it does let one write the following (and without having to update the
Animal
class if new types are added)--To avoid metaclass programming, one could use composition over inheritance. For example--
If the
Dog
andCat
classes need access to theAnimal
instance, you could also adjust thetype_instance()
method above to pass what it needs to the class constructor (e.g.self
).thedk 提出的元类方法确实是一种非常强大的方法,但是,我必须将其与问题的答案结合起来 此处让查询返回代理模型实例。适用于前面示例的代码的简化版本是:
这种代理方法的优点是创建新子类时不需要数据库迁移。缺点是子类中不能添加特定的字段。
我很高兴收到有关此方法的反馈。
The Metaclass approach proposed by thedk is indeed a very powerful way to go, however, I had to combine it with an answer to the question here to have the query return a proxy model instance. The simplified version of the code adapted to the previous example would be:
The advantage of this proxy approach is that no db migration is required upon creation of new subclasses. The drawback is that no specific fields can be added to the subclasses.
I would be happy to have feedback on this approach.
人类已知的唯一方法是使用元类编程。
这是简短的答案:
以及期望的结果:
它是如何工作的?
动物的名字 - 我们使用
object_class
Django 中的反向关系(不好的
我们创建额外的数据库
每个儿童模型的表格和
为此浪费额外的数据库命中,
好的一面是我们可以添加一些孩子
模型相关字段)
对象的 object_class 中的名称
调用保存。
通过Django中的反向关系
到名称缓存在的模型
对象_类。
每次 Animal 被实例化时
重新定义动物元类
模型。元类就像是
类的模板(就像
类是对象的模板)。
有关 Python 中元类的更多信息:http://www.ibm.com/ developerworks/linux/library/l-pymeta.html
the only way known to the human kind is to use Metaclass programming.
Here is short answer:
and the desired result:
How does it work?
name of the animal - we use
object_class for that
reverse relation in Django (the bad
side of this we create extra DB
table for every child model and
waste additional DB hit for that,
the good side we can add some child
model dependent fields)
name in object_class of the object
that invoke save.
through reverse relation in Django
to the Model with name cached in
object_class.
every time Animal is instantiate by
redefining Metaclass of Animal
model. Metaclass is something like a
template for a class (just like a
class is a template for an object).
More information about Metaclass in Python: http://www.ibm.com/developerworks/linux/library/l-pymeta.html