Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Proxy Field

Tags:

python

django

Is it possible to make a Django Proxy Field that has access to another field, but doesn't save anything to the database for it's own value(s), and doesn't have a database column for itself?

The use case for this is we'd like to store values in a JsonField, but be able to use the built in validations of Django Fields. A second benefit of this would being able to add new fields (with validation capability) without affecting the database schema.

The sudo code would probably look something like this:

from django.db import models
from django.contrib.postgres.fields import JsonField

class ProxyInitMixin(object):

    def __init__(self, *args, *kwargs):
        # some logic that will hold values if set on the Model
        # but won't create a column or save anything to the
        # database for this Field.
        super(ProxyInitMixin, self).__init__(*args, **kwargs)

class ProxyIntegerField(ProxyInitMixin, models.Field):
    pass

class ProxyCharField(ProxyInitMixin, models.Field):
    pass

class MyModel(models.Model):
    proxy_int = ProxyIntegerField()
    proxy_char = ProxyCharField()
    data = JsonField()

    def save(self, *args, **kwargs):
        self.data = {
            'foo': self.proxy_int,
            'bar': self.proxy_char
        }
        return super(MyModel, self).save(*args, **kwargs)
like image 477
Aaron Lelevier Avatar asked May 24 '16 23:05

Aaron Lelevier


1 Answers

There are proxy models in django, But I am not sure if it has something like proxy fields.

For your use case, you can do as mentioned below:

  1. Create a list of fields with each field containing name, type, nullable, etc.
  2. Add a function in your model to return actual django rest framework (DRF) field class instance, corresponding to each field type passed to it.
  3. Use DRF inbuilt field class validation to validate your field data against specified field type in save().
  4. In addition to automatic validation, you will also get automatic type conversion. Eg. If user entered number 1 as text: "1" for a integer field then it will automatically convert it back to integer 1. Same way, it will work for float, Bool, Char, etc

`

from django.db import models
from rest_framework.fields import IntegerField, FloatField, BooleanField, DateTimeField, CharField

class MyModel(models.Model):
    FIELDS = [{'field_name': 'proxy_int', 'field_type': 'int', 'null_allowed': 'True'},
              {'field_name': 'proxy_char', 'field_type': 'string', 'null_allowed': 'True'}]

    data = JsonField()

    def field_type(self, field):

        if field.field_type == 'int':
            return IntegerField()
        elif field.field_type == 'float':
            return FloatField()
        elif field.field_type == 'bool':
            return BooleanField()
        elif field.field_type == 'date':
            return DateTimeField()
        elif self.value_type == 'string':
            return CharField()
        return CharField()

    def save(self, *args, **kwargs):
        data = kwargs.get('data', {})
        new_data = {}

        for (field in FIELDS)

            field_name = field['field_name']
            field_type = field['field_type']
            field_value = data.get(field_name, None)

            validated_value = self.field_type(field_type).run_validation(field_value)

            new_data[field_name] = validated_value

        kwargs['data'] = new_data
        return super(MyModel, self).save(*args, **kwargs)`

You may try and figure out django's field classes (Instead of DRF) and use them for validation, if required.

You can inherit this new MyModel class to achieve similar capability in other models and to reuse code.

like image 90
satyam verma Avatar answered Oct 20 '22 23:10

satyam verma