Suppose I want to do some extra stuff whenever a model is created in my Django App:
models.py:
class MyModel(models.Model):
name = models.CharField(max_length=255)
def do_some_extra_stuff(self):
// whatever...
return "I did some extra stuff"
Suppose the extra stuff is some long-running asynchronous task.
I am using Django Rest Framework and have a standard ModelSerializer
and ViewSet
.
My question is where is the best place to put the call to do_some_extra_stuff
? I can think of the following options:
- In the serializer.create method
- In the viewset.create method
- In the model.save method
- In a post_save signal
I am leaning towards #1 or #2 b/c I only want this fn to be called when normal users interact w/ the API - not when using the Django Admin or the shell.
CodePudding user response:
This question will probably be closed because its opinion based, so here are my opinions on it!
Background Tasks
Celery is "better", but Django-RQ (and RQ itself) is almost always enough if you have good logging and error reporting. These aren't usually bank account transfers we're dealing with.
#2 - Viewset Based
I believe serializers should only serialize & validate. Because of this, any custom save logic needs to go in the ViewSet
- up front, visible at the point use, and has access to everything without any serializer context tricks.
class MyViewSet(ModelViewSet):
def perform_create(self, serializer):
# pass a value into save(), which passes it to model.create()
serializer.save(org_id=self.request.user.secret_org_id)
# use the serializer instance that was created to enqueue a bg task
my_background_task.delay(item_pk=serializer.instance.pk)
This is just a preference. Its perfectly fine to put it in the serializer if that is how you normally do other tasks. The only goal is consistency.
This may make more sense if you imagine using 1 serializer for each action - list
, create
, and update
.
Other Methods
#3 In the model.save method
The model.save()
is not called in some rare cases, and its not the place I expect to see logic that runs other tasks. Some model field cleanups work there. Again this is a preference, but using this method with DRF seems unusual, as opposed to when you are in pure django and using the admin site.
#4 In a post_save signal
I feel post-save signals are too far away from the model, and also not called in some rare cases (same mostly as #3). I would rather be explicit with things like this, so I keep it close to where I expect to see it happen. We use post_save signals for other things, but they do suffer from not being able to see the context, and its difficult to pass additional parameters into them.