Django查询集中如何区分子对象

3
我有一个名为“Block”的模型。
class Block(models.Model):
zone = models.ForeignKey(Zone)
order = models.IntegerField()
weight = models.IntegerField()
block_type = models.CharField(max_length=32, blank=True)

class Meta:
    ordering = ['order']

def __str__(self):
    return "Block "+str(self.order)

Block对象有一些从它继承的子元素,比如ImageBlock, VideoBlock等,在项目进行时我会继续添加更多。

# Children of Block Object
class TextBlock(Block):
    content = models.TextField(blank=True)

class ImageBlock(Block):
    content = models.ImageField(blank=True)

class VideoBlock(Block):
    content = models.FileField(blank=True)

我需要根据块的顺序执行操作。例如,

渲染TextBlock1 渲染ImageBlock1 渲染TextBlock2

我使用类似于Block.objects.all()的方式查询所有这些对象,然后逐个迭代。在这样做时,如何区分它们中的每个对象?

例如:

blockset = Block.objects.all()
for block in blockset:
    if (**some way of differentiating if it's a TextBlock**):
        print("This is a text block!")

有任何想法如何去做这件事吗?
非常感谢!

“block_type”是什么?难道你不使用它来确定类型吗? - Glyn Jackson
这可能比你需要的多或少,但你可能会对django_model_utils包感兴趣,这样你就可以做像这样的事情。 - Two-Bit Alchemist
1个回答

3
如果您不知道要获取的类名,可以在父模型上使用 内容类型。例如:

(未经测试)

from django.contrib.contenttypes.models import ContentType

class Block(models.Model):
   zone = models.ForeignKey(Zone)
   order = models.IntegerField()
   weight = models.IntegerField()
   block_type = models.ForeignKey(ContentType, editable=False)

   def save(self, *args, **kwargs):
        if not self.id:
            self.block_type = self._block_type()
        super(Block, self).save(*args, **kwargs)

   def __block_type(self):
        return ContentType.objects.get_for_model(type(self))

    def cast(self):
        return self.block_type.get_object_for_this_type(pk=self.pk)

    class Meta:
        abstract = True

此外,请注意抽象基类,这意味着模型不会在数据库中创建。抽象字段将添加到子类的字段中,即。
class TextBlock(Block):
    content = models.TextField(blank=True)

然而,在这个例子中,您无法查询抽象基类。如果这正是您想要做的事情,那么只需在基类上添加一个查找即可。

 TEXT = 'TXT'
 IMAGE = 'IMG'
 VIDEO = 'VID'
 BLOCK_CHOICES = (
        (TEXT, 'Text Block'),
        (IMAGE, 'Image Block'),
        (VIDEO, 'Video Block'),
    )

class Block(models.Model):
    zone = models.ForeignKey(Zone)
    order = models.IntegerField()
    weight = models.IntegerField()
    block_type = models.CharField(max_length=3, choices=BLOCK_CHOICES)

接下来查询:Block.objects.filter(block_type='Text Block')

或者在您的示例中:

blockset = Block.objects.all()
for block in blockset:
    if block.block_type == "Text Block":
        print("This is a text block!")

1
嗯,我一直希望能够摆脱基础对象的block_type字段,但你说得对,我无法查询抽象类(没有它,ContentType只会返回我的父Block对象的名称)。无论如何,感谢您的澄清,并向我介绍Content Type函数! - Robert Townley
没问题,希望能有所帮助。 - Glyn Jackson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接