How can I launch custom code on POST

1,452 views
Skip to first unread message

Adam G

unread,
Feb 20, 2014, 7:48:34 PM2/20/14
to django-res...@googlegroups.com
I've setup a working REST API following the docs and everything is working great. Now I'd like to kick off a custom task when I POST certain fields into my CurrentTask Model. Here is the model:

class TaskCurrent(models.Model):
    result_code = models.IntegerField()
    start_date_time = models.DateTimeField(blank=True, null=True)
    success = models.BooleanField()
    actual_count = models.IntegerField()
    target_count = models.IntegerField(blank=True, null=True)
    requested_date_time = models.DateTimeField(auto_now_add=True, blank=True)
    run_id = models.IntegerField()
    run_config = models.CharField(max_length=1000, unique=True)
    end_time = models.DateTimeField(blank=True, null=True)

    def __str__(self):
        return "Task ID: {}".format(self.run_id)

It should kick off some custom Python to run when I post into the run_id field, and a run_config field. Those parameters are then passed into my custom code, then the code will update the model during the course of its function finally ending with a filling out the success fields, and result_code fields. What is the best way to approach this? It's kinda hard to google since I don't know if I'm using the right language. Hopefully this post makes sense, if there's another approach to this particular workflow, I'm happy to change it.


Thanks,
Adam

Tim Watts

unread,
Feb 20, 2014, 8:31:56 PM2/20/14
to django-rest-framework
Hey Adam, It's a bit hard to say without knowing more about how your
views are set up, but you have a few options.
1) A simple api view
http://www.django-rest-framework.org/api-guide/views#@api_view()

@api_view(['POST'])
def run_task(request):
foo = request.POST.get('foo', None)
if foo:
# do something
return Response({"status": "It worked"})


2) Use generic view and override the methods that you'll be calling.
Likely either 'post', 'create', or 'update'.
http://www.django-rest-framework.org/api-guide/generic-views

3) Override 'save' on your django model. There you can check the
values on whatever fields on that specific model has and run your task
then.

It may be overkill, but if your tasks are long running, you could look
into asynchronous task queue. I would recommend Celery [0] but RQ
looks interesting as well [1]
[0] http://docs.celeryproject.org/en/latest/index.html
[1] http://python-rq.org/

Adam G

unread,
Feb 21, 2014, 3:25:53 PM2/21/14
to django-res...@googlegroups.com
Hi Tim,

Thanks for the options you pointed out. The more I look at this use case, the more celery looks like the right solution. Until then I'll try the other options, starting with number 2. I'm using a class view that inherits the viewsets.ModelViewSet and I'll try overriding the create method to call my code in that function.

I have plenty to work  with and will follow up with my solution for posterity.

Thanks again! Cheers!

Adam G

unread,
Feb 21, 2014, 5:52:11 PM2/21/14
to django-res...@googlegroups.com
Overriding the create method worked like a charm. However the requirements have changed, and I no longer need to launch on POST. For what it's worth if you use a viewset that inherits from viewsets.ModelViewSet then copy the create method from the inherited mixins.CreateModelMixin and add the code there. Beware that the code will block, here's what I mean:

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.DATA,
                                         files=request.FILES)

        if serializer.is_valid():
            self.pre_save(serializer.object)
            self.object = serializer.save(force_insert=True)
            self.post_save(self.object, created=True)
            #run code here, but it will stop everything until it runs
            #for example this will make django unresponsive for 100 seconds
            #time.sleep(100)
            #so maybe run your code in a thread or async process
            #or maybe throw a decorator over the create method that handles the async task?
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED,
                            headers=headers)

Cheers
Reply all
Reply to author
Forward
0 new messages