1

I have an "abstract" model class MyField:

class MyField(models.Model):
    name = models.CharField(db_index = True, max_length=100)
    user = models.ForeignKey("AppUser", null=False)

I have a few other subclasses of MyField each defining a value of a specific type. for example:

class MyBooleanField(MyField):
    value = models.BooleanField(db_index = True, default=False)

In MyField I have a method get_value() that returns the value based on the specific subclass.

In django rest I want to fetch all the fields of a user

class AppUserSerializer(serializers.ModelSerializer):
    appuserfield_set = MyFieldSerializer(many=True)
    class Meta:
        model = AppUser
        fields = ('appuser_id', 'appuserfield_set')    

On the client side I want the user to be able to add new fields and set values to them and then on the server I want to be able to create the correct field based on the value.

What is the correct way to achieve this behavior?

1 Answer 1

1

After some digging, here is what I ended up doing. Aside from the code below I had to implement get_or_create and create the relevant subclass of MyField based on the passed value.

class ValueField(serializers.WritableField):
  #called when serializing a field to a string. (for example when calling seralizer.data)
  def to_native(self, obj):
    return obj;

  """
  Called when deserializing a field from a string
  (for example when calling is_valid which calles restore_object)
  """
  def from_native(self, data):
    return data


class MyFieldSerializer(serializers.ModelSerializer):
  value = ValueField(source='get_value', required=False)    

  def restore_object(self, attrs, instance=None):
    """
    Called by is_valid (before calling save)
    Create or update a new instance, given a dictionary
    of deserialized field values.

    Note that if we don't define this method, then deserializing
    data will simply return a dictionary of items.
    """
    if instance:
        # Update existing instance
        instance.user = attrs.get('user', instance.user)
        instance.name = attrs.get('name', instance.name)
    else:
        # Create new instance
        instance = MyField.get_or_create(end_user=attrs['user'],
                                            name=attrs['name'],
                                            value=attrs['get_value'])[0]

    instance.value = attrs['get_value']
    return instance

  def save_object(self, obj, **kwargs):
    #called when saving the instance to the DB
    instance = MyField.get_or_create(end_user=obj.user,
                                            name=obj.name,
                                            value=obj.value)[0]
  class Meta:
    model = MyField
    fields = ('id', 'user', 'name', 'value')
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.