简体   繁体   English

将属性转换为django模型字段

[英]Convert property to django model field

Is there any way to create virtual model field in django? 有没有办法在django中创建虚拟模型字段?

For example I have 比如我有

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())

Now, if I will run: 现在,如果我将运行:

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

it will work fine. 它会工作正常。

But I have a dump, where I have model A with virtual_field value - on serialization I've got an error "A object has no virtual_field"... How I can cheat serializer and tell it, that virtual_field exists? 但我有一个转储,我有模型A与virtual_field值 - 在序列化我有一个错误“一个对象没有virtual_field”...我怎么可以欺骗序列化器并告诉它,virtual_field存在?

If you want to load from legacy fixture, you could build some intermediate model/table, convert file or customize dumpdata command. 如果要从旧夹具加载,可以构建一些中间模型/表,转换文件或自定义dumpdata命令。 Fool dumpdata is possible, as following, but hmm... 傻瓜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)

Or you could add customized serializer to public serializers and mainly override its Deserializer function to work w/ properties that you have. 或者您可以将自定义序列化程序添加到公共序列化程序,并主要覆盖其Deserializer函数以使用您拥有的属性。 Mainly override to tweak two lines in Deserializer inside django/core/serializers/python.py 主要覆盖在django/core/serializers/python.py中的Deserializer调整两行

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM