Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Virtual Field: set value of a property from a virtual field

I'm trying to understand the internals of django ModelFields to implement a new feature on django-hstore.

Basically I want to create virtual fields from an HStore Dictionary which has a predefined schema.

As a first step, I'd like hide the actual HStore Dictionary field and use instead the value present in the virtual fields to compose the final HStore Dictionary.

I've been able to make the admin work properly for all actions except for the save action, which does not save the value of the virtual field into the HStore dictionary.

Here's my actual VirtualField code:

# virtual.py
from django.db.models.fields import Field


class VirtualField(Field):
    """ Virtual Field """

    def __init__(self, *args, **kwargs):
        try:
            self.hstore_field_name = kwargs.pop('hstore_field_name')
        except KeyError:
            raise ValueError('missing hstore_field_name keyword argument')
        super(VirtualField, self).__init__(*args, **kwargs)

    def contribute_to_class(self, cls, name, virtual_only=True):
        super(VirtualField, self).contribute_to_class(cls, name, virtual_only)

    def value_from_object(self, obj):
        """
        Returns the value of this field in the given model instance.
        """
        hstore_field = getattr(obj, self.hstore_field_name)
        return hstore_field[self.attname]

    def save_form_data(self, instance, data):
        hstore_field = getattr(instance, self.hstore_field_name)
        hstore_field[self.attname] = data
        setattr(instance, self.hstore_field_name, hstore_field)

models.py (just prototyping)

class ModeledDataBag(models.Model):
    name = models.CharField(max_length=32)
    data = hstore.ModeledDictionaryField(schema={
        'number': {
            'type': int,
            'default': 0
        }
    })

    number = VirtualField(hstore_field_name='data')

    objects = hstore.HStoreManager()

I thought save_form_data would do the trick but that's not true.

In the django docs i've found "The SubfieldBase metaclass" section in the "Custom Model Fields" page which looks like what I need.

Is it that the right path to follow?

Is there any example to study?

Anyone can provide an example of how to set the value of the key "number" of the hstore field "data" and store it in the database? From there I think I know how to go ahead.

Thanks...

like image 214
nemesisdesign Avatar asked Oct 20 '22 06:10

nemesisdesign


1 Answers

The right answer was to use python descriptors, the implemented solution is here:

https://github.com/djangonauts/django-hstore/blob/8229e850e1631d8fd038436d2aa1fccb26b9a699/django_hstore/virtual.py#L29

This feature was originally developed for an open source project called nodeshot, here's an example implementation with the schema taken from settings.py:

https://github.com/ninuxorg/nodeshot/blob/028bb28009bf73b2a4fc087f811e1b66c958907e/nodeshot/core/nodes/models/node.py#L49

like image 200
nemesisdesign Avatar answered Oct 27 '22 09:10

nemesisdesign