2011-09-21 52 views
4

有没有什么方法可以在django中创建虚拟模型字段?将属性转换为django模型字段

比如我有

class A(models.Model): 
    field_1 = models.CharField(max_length=100) 
    field_2 = models.CharField(max_length=100) 

    @apply 
    def virtual_field(): 
     def fget(self): 
      return self.field1 + '/' + self.field2 
     def fset(self, value): 
      self.field_1, self_field_2 = value.split('/') 
      return True 
     return property(**locals()) 

现在,如果我将运行:

a = A() 
a.virtual_field = '5/5' 
a.save() 

它将很好地工作。

但我有一个转储,我有模型A与virtual_field值 - 序列化我有一个错误“一个对象没有virtual_field”...我如何可以欺骗串行器,并告诉它,该virtual_field存在?

+0

您使用哪个序列化程序? – rumpel

+0

标准django序列化程序,它调用test,loaddata。 –

+0

只是想知道为什么你想序列化一个虚拟的领域。它可以从'field1'和'field2'获得值。 – okm

回答

4

如果您想从传统灯具加载,您可以构建一些中间模型/表格,转换文件或自定义dumpdata命令。傻瓜dumpdata是可能的,如下面的,但嗯...

class VirtualField(object): 
    rel = None 

    def contribute_to_class(self, cls, name): 
     self.attname = self.name = name 
     # cls._meta.add_virtual_field(self) 
     get_field = cls._meta.get_field 
     cls._meta.get_field = lambda name, many_to_many=True: self if name == self.name else get_field(name, many_to_many) 
     models.signals.pre_init.connect(self.pre_init, sender=cls) #, weak=False) 
     models.signals.post_init.connect(self.post_init, sender=cls) #, weak=False) 
     setattr(cls, name, self) 

    def pre_init(self, signal, sender, args, kwargs, **_kwargs): 
     sender._meta._field_name_cache.append(self) 

    def post_init(self, signal, sender, **kwargs): 
     sender._meta._field_name_cache[:] = sender._meta._field_name_cache[:-1] 

    def __get__(self, instance, instance_type=None): 
     if instance is None: 
      return self 
     return instance.field1 + '/' + instance.field2 

    def __set__(self, instance, value): 
     if instance is None: 
      raise AttributeError(u"%s must be accessed via instance" % self.related.opts.object_name) 
     instance.field1, instance.field2 = value.split('/') 

    def to_python(self, value): 
     return value 

class A(models.Model): 
    field1 = models.TextField() 
    field2 = models.TextField() 
    virtual_field = VirtualField() 

# legacy.json 
[{"pk": 1, "model": "so.a", "fields": {"virtual_field": "A/B"}}, {"pk": 2, "model": "so.a", "fields": {"virtual_field": "199/200"}}] 

$ ./manage.py loaddump legacy.json 
Installed 2 object(s) from 1 fixture(s) 

或者你可以自定义的串行增加公共串行和主要覆盖其Deserializer功能工作瓦特/你有属性。主要覆盖在Deserializer内部调整两行django/core/serializers/python.py

field = Model._meta.get_field(field_name) 
# and 
yield base.DeserializedObject(Model(**data), m2m_data) 
+0

这帮助我更好地了解灯具。谢谢。 –