【问题标题】:using django, how do i construct a proxy object instance from a superclass object instance?使用 django,我如何从超类对象实例构造代理对象实例?
【发布时间】:2010-10-13 05:03:34
【问题描述】:

我仍然对代理模型与其在 django 中的超类的关系感到有些困惑。我现在的问题是如何从已经检索到的超类实例中获取代理模型的实例?

所以,假设我有:

class Animal(models.Model):
   type = models.CharField(max_length=20)
   name = models.CharField(max_length=40)

class Dog(Animal):  
   class Meta:
       proxy = True

   def make_noise(self):  
       print "Woof Woof"  

Class Cat(Animal):  
   class Meta:
       proxy = True

   def make_noise(self):  
       print "Meow Meow"

animals = Animal.objects.all()
for animal in animals:
   if (animal.type == "cat"):
      animal_proxy = # make me a cat
   elif (animal.type == "dog"):
      animal_proxy = # make me a dog
   animal_proxy.make_noise()

好的。所以..“#让我成为一只猫”不需要查询回数据库,例如:

animal_proxy = Cat.objects.get(id=animal.id)

有没有一种简单的方法可以从我知道是猫的 Animal 实例创建 Cat 实例?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    您正在尝试为继承层次结构实现持久性。使用一个混凝土表和一个type 开关是一种很好的方法。但是我认为你的实现,具体来说:

    for animal in animals:
       if (animal.type == "cat"): 
          animal_proxy = # make me a cat
    

    与 Django 背道而驰。开启类型不应与代理(或模型)类无关。

    如果我是你,我会这样做:

    首先,向代理模型添加“类型感知”管理器。这将确保Dog.objects 将始终使用type="dog" 获取Animal 实例,而Cat.objects 将使用type="cat" 获取Animal 实例。

    class TypeAwareManager(models.Manager):
        def __init__(self, type, *args, **kwargs):
            super(TypeAwareManager, self).__init__(*args, **kwargs)
            self.type = type
    
        def get_query_set(self):
            return super(TypeAwareManager, self).get_query_set().filter(
                  type = self.type)
    
    class Dog(Animal):
        objects = TypeAwareManager('dog')
        ...
    
    class Cat(Animal):
        objects = TypeAwareManager('cat')
        ...
    

    其次,分别获取子类实例。然后,您可以在对它们进行操作之前将它们组合起来。我用itertools.chain 合并了两个Querysets

    from itertools import chain
    q1 = Cat.objects.all() # [<Cat: Daisy [cat]>]
    
    q2 = Dog.objects.all() # [<Dog: Bruno [dog]>]
    
    for each in chain(q1, q2): 
        each.make_noise() 
    
    # Meow Meow
    # Woof Woof
    

    【讨论】:

    • 我知道我违背了 Django 的原则。我这样做是因为 Django 不允许我做我想做的事,即获取存储在同一个表中但具有不同属性的对象列表,而实际上没有将结果链接在一起。我构建了一个类型感知管理器,但在超类级别,现在我只需要将返回的超类对象实例“转换”为代理类对象。有没有办法做到这一点?
    • 实际上,我已经这样做了,但我目前正在按照以下方式回调数据库:animal_proxy = Cat.objects.get(id=animal.id) 我想要类似 animal_proxy = (猫)动物。我知道必须有 python 诡计可以为我做到这一点。
    • @Bubba:看到这个问题。您可能会感兴趣的答案。 stackoverflow.com/questions/2218867/…
    • 我看到了这个问题。我的例子是基于这个问题。
    • 我已经通过在 Animal 类上破解查询集来获取混合的 Cat+Dog 结果。我只是想避免在从查询集返回的 Animal 实例中实例化 Cat+Dog 时调用数据库。
    【解决方案2】:

    我愿意:

    def reklass_model(model_instance, model_subklass):
    
        fields = model_instance._meta.get_all_field_names()
        kwargs = {}
        for field_name in fields:
            try:
               kwargs[field_name] = getattr(model_instance, field_name)
            except ValueError as e: 
               #needed for ManyToManyField for not already saved instances
               pass
    
        return model_subklass(**kwargs)
    
    animals = Animal.objects.all()
    for animal in animals:
       if (animal.type == "cat"):
          animal_proxy = reklass_model(animal, Cat)
       elif (animal.type == "dog"):
          animal_proxy = reklass_model(animal, Cat)
       animal_proxy.make_noise()
    
    # Meow Meow
    # Woof Woof
    

    我没有用“动物园”测试过它;)但是用我自己的模型似乎可以工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-16
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      • 2019-12-14
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多