【问题标题】:Django custom field with multiple inheritance具有多重继承的Django自定义字段
【发布时间】:2011-07-28 07:27:17
【问题描述】:

我有两个自定义 Django 字段,一个 JSONField 和一个 CompressedField,它们都运行良好。我也想有一个CompressedJSONField,我更希望我能做到这一点:

class CompressedJSONField(JSONField, CompressedField):
    pass

但在导入时我得到:

RuntimeError: maximum recursion depth exceeded while calling a Python object

我可以找到有关在 Django 中使用具有多重继承的模型的信息,但没有关于对字段执行相同操作的信息。这应该可能吗?还是应该在这个阶段就放弃?

编辑:

为了清楚起见,我不认为这与我的代码的细节有任何关系,因为以下代码具有完全相同的问题:

class CustomField(models.TextField, models.CharField):
    pass

编辑 2:

我目前使用的是 Python 2.6.6 和 Django 1.3。这是我的剥离右下测试示例的完整代码:

customfields.py

from django.db import models


class CompressedField(models.TextField):
    """ Standard TextField with automatic compression/decompression. """

    __metaclass__ = models.SubfieldBase
    description = 'Field which compresses stored data.'

    def to_python(self, value):
        return value

    def get_db_prep_value(self, value, **kwargs):
        return super(CompressedField, self)\
                        .get_db_prep_value(value, prepared=True)


class JSONField(models.TextField):
    """ JSONField with automatic serialization/deserialization. """

    __metaclass__ = models.SubfieldBase
    description = 'Field which stores a JSON object'

    def to_python(self, value):
        return value

    def get_db_prep_save(self, value, **kwargs):
        return super(JSONField, self).get_db_prep_save(value, **kwargs)


class CompressedJSONField(JSONField, CompressedField):
    pass

models.py

from django.db import models
from customfields import CompressedField, JSONField, CompressedJSONField

class TestModel(models.Model):

    name = models.CharField(max_length=150)
    compressed_field = CompressedField()
    json_field = JSONField()
    compressed_json_field = CompressedJSONField()

    def __unicode__(self):
        return self.name

我一添加compressed_json_field = CompressedJSONField() 行,就会在初始化 Django 时出错。

【问题讨论】:

  • 除非您发布JSONFieldCompressedField 的代码,否则无法判断发生了什么
  • @pajton:我认为该代码无关紧要——请参阅我的编辑。 (不过,如果你真的想看,我很乐意发布它:))
  • 嗯,有趣...我不知道为什么会这样
  • 是“传递”给你错误的实际代码吗?自定义字段保存和导入到哪里?
  • @kriegar -- 是的,有问题的代码就像我展示的那样简单。对不起,但我想我不明白你的另一个问题。该代码位于一个单独的模块中,并在我的models.py 顶部使用from custom_field import CustomField 调用,如果这就是您的意思...

标签: python django multiple-inheritance custom-fields


【解决方案1】:

很难理解您何时收到该错误。但是查看 DJango 代码,有类似的实现(多重继承)

参考:类 ImageFieldFile(ImageFile, FieldFile)
在 django/db/models/fields 中

【讨论】:

  • 您能否提供更多信息和解释,而不仅仅是对示例链接的引用?
  • ImageFieldFile 是类文件类,而不是字段类(ImageFileFieldFile 也是如此)。图像字段类称为ImageField,它继承自FileField,而FileField 又继承自Field。据我所知,所有标准字段类的名称都以 Field 结尾。
【解决方案2】:

在做了一些快速测试后,我发现如果您从 JSON 和压缩字段中删除 元类 并将其放入压缩的 JSON 字段中,它会编译。如果您随后需要 JSON 或 Compressed 字段,则将它们子类化并添加 __metaclass__ = models.SubfieldBase

我不得不承认我没有对此进行任何繁重的测试:

from django.db import models                                                       


class CompressedField(models.TextField):                                           
    """ Standard TextField with automatic compression/decompression. """           

    description = 'Field which compresses stored data.'                            

    def to_python(self, value):                                                    
        return value                                                               

    def get_db_prep_value(self, value, **kwargs):                                  
        return super(CompressedField, self).get_db_prep_value(value, prepared=True)


class JSONField(models.TextField):                                                 
    """ JSONField with automatic serialization/deserialization. """                

    description = 'Field which stores a JSON object'                               

    def to_python(self, value):                                                    
        return value 

    def get_db_prep_save(self, value, **kwargs):                                   
        return super(JSONField, self).get_db_prep_save(value, **kwargs)            


class CompressedJSONField(JSONField, CompressedField):                             
    __metaclass__ = models.SubfieldBase                                            

class TestModel(models.Model):                                                     

    name = models.CharField(max_length=150)                                        
    #compressed_field = CompressedField()                                          
    #json_field = JSONField()                                                      
    compressed_json_field = CompressedJSONField()                                  

    def __unicode__(self):                                                         
        return self.name

如果您想分别使用 JSON 和 Commpressed 字段,我认为这个想法会奏效:

class JSONFieldSubClass(JSONField):
    __metaclass__ = models.SubfieldBase

老实说......我真的不明白这些。

编辑基本方法技巧

class CompressedJSONField(JSONField, CompressedField):
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        value = JSONField.to_python(self, value)
        value = CompressedField.to_python(self, value)
        return value

另一种方法是使类上的 to_python() 具有唯一名称,并在继承的类 to_python() 方法中调用它们

或者看看这个answer

编辑 经过一番阅读,如果您在第一个基地 to_python() 中实现对super(class, self).method(args) 的调用,那么它将调用第二个基地。如果您使用超级一致,那么您应该没有任何问题。 http://docs.python.org/library/functions.html#super 值得一试,http://www.artima.com/weblogs/viewpost.jsp?thread=237121

class base1(object):                                                               
    def name(self, value):                                                         
        print "base1", value                                                       
        super(base1, self).name(value)                                             

    def to_python(self, value):                                                    
        value = value + " base 1 "                                                 
        if(hasattr(super(base1, self), "to_python")):                              
            value = super(base1, self).to_python(value)                            
        return value                                                               

class base2(object):                                                               
    def name(self, value):                                                         
        print "base2", value                                                       

    def to_python(self, value):                                                    
        value = value + " base 2 "                                                 
        if(hasattr(super(base2, self), "to_python")):                              
            value = super(base2, self).to_python(value)                            
        return value                                                               

class superClass(base1, base2):                                                    
    def name(self, value):                                                         
        super(superClass, self).name(value)                                        
        print "super Class", value    

【讨论】:

  • 这很有帮助,谢谢。我花了一些时间漫无目的地摆弄东西,看看我是否可以让它工作,但我没有尝试这个!我担心的是,在这种情况下,每个类的 to_python() 方法会被正确调用吗? (This, of course, is the main point of these particular fields.) 不过,我现在有一些工作要做,谢谢!
  • @simon 我不知道哪个会被调用.. 但只有一种方法可以找出答案。让我们知道会发生什么! ;)
  • @simon python docs 似乎暗示第一个基类具有优先权。但正如我所说,这主要超出了我的 Python 知识水平。
  • @james -- 我关心的不是它们被调用的顺序,而是它们是否会被调用。我现在有机会对此进行正确测试,并且以这种方式设置,只调用第一个父级的方法:(所以我回到了第一个:(
  • @simon 有一个 hack。我将其添加到帖子中,以便您更好地阅读。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 2012-03-04
  • 2017-01-28
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多