wim
wim

Reputation: 362847

Create an instance from serializer without persisting it to db

Working in the context of creating a django model:

# Creates potato and saves a row to db
spud = Potato.objects.create(...)

# Also creates a potato instance, but doesn't hit db yet.
# Could call `spud.save()` later if/when we want that.
spud = Potato(...)

In factory boy we also have an analogy for this Djangoism

# Returns a saved instance
spud = PotatoFactory.create()

# Returns an instance that's not saved
spud = PotatoFactory.build()

In rest framework v3.3.2, I can't find the analogy. Is it possible?

serializer = PotatoSerializer(data=...)

# creates the instance and saves in db
serializer.create(serializer.validated_data)

I can write my own, something like this:

class PotatoSerializer:
    ...
    def build(self, validated_data):
        return self.Meta.model(**validated_data)

But it's a drag not to have it on the base serializer, am I missing something?

Upvotes: 13

Views: 2764

Answers (3)

knite
knite

Reputation: 6171

From https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/serializers.py#L811-L846 (comments omitted):

def create(self, validated_data):
    raise_errors_on_nested_writes('create', self, validated_data)

    ModelClass = self.Meta.model

    info = model_meta.get_field_info(ModelClass)
    many_to_many = {}
    for field_name, relation_info in info.relations.items():
        if relation_info.to_many and (field_name in validated_data):
            many_to_many[field_name] = validated_data.pop(field_name)

    try:
        instance = ModelClass.objects.create(**validated_data)

The serializer create() method is a fairly thin wrapper around the model's create() method.

The bad news is that you're right, there's no memory-only serializer shortcut for:

class PotatoSerializer:
    ...
    def build(self, validated_data):
        return self.Meta.model(**validated_data)

The good news is that you can cut out the middle man and call the model directly:

Potato(**validated_data)

Upvotes: 1

Soufiaane
Soufiaane

Reputation: 2097

in your PotatoSerializer, you need to override the Create method. something like this:

class PotatoSerializer:
    ...
    class Meta:
        ...

    def create(self, validated_data):
        # and here you change the default behavior of the serializer
        return Potato(**validated_data)
            # instead of
            # return Potato.objects.create(**validated_data)

Upvotes: 0

Linovia
Linovia

Reputation: 20976

Default Serializer do save to the database. However, if you want to test against the validation, a simple call to is_valid will do and avoid saving to the database.

I'm mostly guessing as your question isn't very clear regarding your goal.

Upvotes: 0

Related Questions