Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django-检查多表继承查询集的类型_Python_Django_Database Design - Fatal编程技术网

Python Django-检查多表继承查询集的类型

Python Django-检查多表继承查询集的类型,python,django,database-design,Python,Django,Database Design,我试图在我的数据库中保存一种目录结构。简化示例: models.py class Section (models.Model): title = models.CharField(max_length=80) order = models.IntegerField() class SectionClickable(Section): link = models.CharField(max_length=80) class SectionHeading(Section)

我试图在我的数据库中保存一种目录结构。简化示例:

models.py

class Section (models.Model):
    title = models.CharField(max_length=80)
    order = models.IntegerField()

class SectionClickable(Section):
    link = models.CharField(max_length=80)

class SectionHeading(Section):
    background_color = models.CharField(max_length=6)
views.py

sections = Section.objects.filter(title="Hello!")
for section in sections:
        if(section.sectionheading):
            logger.debug("It's a heading")
如果是
SectionHeading
实例,我需要执行一些处理操作,但是(如Django手册中所述),访问
节。如果对象不是SectionHeading类型,SectionHeading
将抛出DoesNotExist错误

我一直在寻找这类问题的替代方案,我正在浏览contenttypes包中的通用外键。然而,这似乎会在Django管理端引起更多的麻烦。有人能提出比上述更好的解决方案吗


编辑:由于
顺序
字段,我避免了抽象继承。我必须将两个查询集连接在一起,并按顺序对它们进行排序。您可以检查类型:

if isinstance(section, SectionHeading)
但一般都是首选

编辑:

事实上,这可能行不通。对象将是一个
。但您可以查找该属性:

if hasattr(section, 'sectionheading')


你可以检查一下类型:

if isinstance(section, SectionHeading)
但一般都是首选

编辑:

事实上,这可能行不通。对象将是一个
。但您可以查找该属性:

if hasattr(section, 'sectionheading')


我一直在使用类似于他编辑中建议的内容:

class SomeBaseModel(models.Model):
    reverse_name_cache = models.CharField(_('relation cache'), max_length=10, 
                                          null=True, editable=False)

    def get_reverse_instance(self):
        try:
            return getattr(self, self.reverse_name_cache)
        except AttributeError:
            for name in ['sectionclickable', 'sectionheading']:
                try:
                    i = getattr(self, name)
                    self.reverse_name_cache = name
                    return i
                except ObjectDoesNotExist:
                    pass

现在,这不是很好,但是它从一个中心位置返回子类实例,所以我不需要用
try
包装其他语句。也许可以避免对子类reverse manager名称进行硬编码,但这种方法已经满足了我的需要。

我一直在使用类似于他编辑中建议的内容:

class SomeBaseModel(models.Model):
    reverse_name_cache = models.CharField(_('relation cache'), max_length=10, 
                                          null=True, editable=False)

    def get_reverse_instance(self):
        try:
            return getattr(self, self.reverse_name_cache)
        except AttributeError:
            for name in ['sectionclickable', 'sectionheading']:
                try:
                    i = getattr(self, name)
                    self.reverse_name_cache = name
                    return i
                except ObjectDoesNotExist:
                    pass

现在,这不是很好,但是它从一个中心位置返回子类实例,所以我不需要用
try
包装其他语句。也许可以避免对子类reverse manager名称进行硬编码,但这种方法足以满足我的需要。

我提出的解决方案涉及一个额外字段,指向(相当有用的)
ContentType
类:

class Section(models.Model):
    name = models.CharField(max_length=50)
    content_type = models.ForeignKey(ContentType,editable=False,null=True)

    def __unicode__(self):
        try:
            return self.as_leaf_class().__unicode__()
        except:
            return self.name

    def save(self, *args, **kwargs):
        if(not self.content_type):
            self.content_type = ContentType.objects.get_for_model(self.__class__)
        super(Section, self).save(*args, **kwargs)

    def as_leaf_class(self):
        content_type = self.content_type
        model = content_type.model_class()
        if(model == Section):
            return self
        return model.objects.get(id=self.id)

如果您使用的是“base”对象,我认为这个解决方案非常好用。

我提出的解决方案涉及一个额外的字段,指向(非常有用的)
ContentType
类:

class Section(models.Model):
    name = models.CharField(max_length=50)
    content_type = models.ForeignKey(ContentType,editable=False,null=True)

    def __unicode__(self):
        try:
            return self.as_leaf_class().__unicode__()
        except:
            return self.name

    def save(self, *args, **kwargs):
        if(not self.content_type):
            self.content_type = ContentType.objects.get_for_model(self.__class__)
        super(Section, self).save(*args, **kwargs)

    def as_leaf_class(self):
        content_type = self.content_type
        model = content_type.model_class()
        if(model == Section):
            return self
        return model.objects.get(id=self.id)
如果您使用的是“基本”对象,我认为这个解决方案非常好,使用起来也很舒服。

OP here

虽然
second
的答案对这个问题是正确的,但我想补充一点,我认为多表继承对于这个场景来说是一种低效的方法。访问子类模型的属性将导致发生查询-因此需要对返回的每一行进行查询。哎哟据我所知,
select\u related
还不能用于多表继承

我还排除了ContentTypes,因为这样做不够优雅,而且似乎还需要很多查询

我决定使用一个抽象类:

class Section (models.Model):
    title = models.CharField(max_length=80)
    order = models.IntegerField()

    class Meta:
        abstract=True
        ordering=['order']
查询了两个表:

section_clickables = SectionClickable.objects.filter(video=video)
section_headings= SectionHeading.objects.filter(video=video)
把两个Queryset连在一起

#Join querysets http://stackoverflow.com/questions/431628/how-to-combine-2-or-more-querysets-in-a-django-view
s = sorted(chain(section_headings, section_clickables), key=attrgetter('order'))
最后,我制作了一个模板标记来检查实例:

from my.models import SectionHeading, SectionClickable

@register.filter()
def is_instance(obj, c):
    try:
        return isinstance(obj, eval(c))
    except:
        raise ObjectDoesNotExist('Class supplied to is_instance could not be found. Import it in the template tag file.')
因此,在我的模板()中,我可以这样做:

- if s|is_instance:"SectionClickable"
    %span {{s.title}}
- if s|is_instance:"SectionHeading"
    %span{'style':'color: #{{s.color}};'}
      {{s.title}}
结果是,我只使用了两个查询,一个用于获取可单击的
节对象,另一个用于此处的
节标题
对象

虽然
second
的答案对这个问题是正确的,但我想补充一点,我认为多表继承对于这个场景来说是一种低效的方法。访问子类模型的属性将导致发生查询-因此需要对返回的每一行进行查询。哎哟据我所知,
select\u related
还不能用于多表继承

我还排除了ContentTypes,因为这样做不够优雅,而且似乎还需要很多查询

我决定使用一个抽象类:

class Section (models.Model):
    title = models.CharField(max_length=80)
    order = models.IntegerField()

    class Meta:
        abstract=True
        ordering=['order']
查询了两个表:

section_clickables = SectionClickable.objects.filter(video=video)
section_headings= SectionHeading.objects.filter(video=video)
把两个Queryset连在一起

#Join querysets http://stackoverflow.com/questions/431628/how-to-combine-2-or-more-querysets-in-a-django-view
s = sorted(chain(section_headings, section_clickables), key=attrgetter('order'))
最后,我制作了一个模板标记来检查实例:

from my.models import SectionHeading, SectionClickable

@register.filter()
def is_instance(obj, c):
    try:
        return isinstance(obj, eval(c))
    except:
        raise ObjectDoesNotExist('Class supplied to is_instance could not be found. Import it in the template tag file.')
因此,在我的模板()中,我可以这样做:

- if s|is_instance:"SectionClickable"
    %span {{s.title}}
- if s|is_instance:"SectionHeading"
    %span{'style':'color: #{{s.color}};'}
      {{s.title}}

结果是我只使用了两个查询,一个用于获取可点击的
节对象,另一个用于
节标题
对象

如何关联
节和
节标题
s?节标题是节的子类如何关联
节和
节标题
s?节标题是节的子类