Django custom field with multiple inheritance
I have two custom Django fields, a JSONField
and a CompressedField
, both of which work well. I would like to also have a CompressedJSONField
, and I was rather hoping I could do this:
class CompressedJSONField(JSONField, CompressedField):
pass
but on import I get:
RuntimeError: maximum recursion depth exceeded while calling a Python object
I can find information about using models with multiple inheritance in Django, but nothing about doing the same with fields. Should this be possible? Or should I just give up at this stage?
edit:
Just to be clear, I don't think this has anything to do with the specifics of my code, as the following code has exactly the same problem:
class CustomField(models.TextField, models.CharField):
pass
edit 2:
I'm using Python 2.6.6 and Django 1.3 at present. Here is the full code of my stripped-right-down test example:
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开发者_StackOverflow_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
as soon as I add the compressed_json_field = CompressedJSONField()
line I get errors when initializing Django.
after doing a few quick tests i found that if you remove the metaclass from the JSON and compressed fields and put it in the compressedJSON field it compiles. if you then need the JSON or Compressed fields then subclass them and jusst add the __metaclass__ = models.SubfieldBase
i have to admit that i didn't do any heavy testing with this:
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
if you then want to uses the JSON and Commpressed fields separately i assume this idea will work:
class JSONFieldSubClass(JSONField):
__metaclass__ = models.SubfieldBase
Honestly ... I don't really understand any of this.
EDIT base method hack
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
the other way is to make the to_python() on the classes have unique names and call them in your inherited classes to_python() methods
or maybe check out this answer
EDIT
after some reading if you implement a call to super(class, self).method(args)
in the first base to_python() then it will call the second base. If you use super consistently then you shouldn't have any problems. http://docs.python.org/library/functions.html#super is worth checking out and 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
It is hard to understand when exactly you are getting that error. But looking at DJango code, there is simlar implementation (multiple inheritance)
refer: class ImageFieldFile(ImageFile, FieldFile)
in django/db/models/fields
精彩评论