1

I'm new to Django and I'm trying to create a somewhat basic API. But one thing that has been bugging me is how to create a callback function for when certain (asynchronous) events occur.

For example, one of my simplest cases is for when the client sends a POST request. I would like to send back to him the ID of that request in the DB. How would I do that?

My code mostly follows William S. Vincent's Django for APIs book with minor modifications.

The most important parts are:

models.py:

from django.db import models

class SegmentcliApi(models.Model): 

    request_id = models.AutoField(primary_key = True)
    database = models.CharField(max_length = 100)
    created_at = models.DateTimeField(auto_now_add = True)
    updated_at = models.DateTimeField(auto_now = True)

    def __str__(self): 

        return f'DB Request to {self.database}: created at {self.created_at}'

serializers.py:

from rest_framework import serializers 
from .models import SegmentcliApi 

class SegmentcliApiSerializer(serializers.ModelSerializer):

    class Meta: 

        fields = (
            'request_id',
            'database',
            'created_at',
            'updated_at',    
        ) 

        model = SegmentcliApi

views.py:

from rest_framework import generics 
from .models import SegmentcliApi
from .serializers import SegmentcliApiSerializer 

class SegmentcliApiList(generics.ListCreateAPIView):

    queryset = SegmentcliApi.objects.all() 
    serializer_class = SegmentcliApiSerializer 

class SegmentcliApiDetail(generics.RetrieveUpdateDestroyAPIView): 

    queryset = SegmentcliApi.objects.all() 
    serializer_class = SegmentcliApiSerializer
Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76

3 Answers3

1

I would suggest starting to look at Django Forms and specifically Model Form, which is what I think SegmentcliApiSerializer is supposed to be. Then, I'm not sure how your urls.py is set up to work with your app, but in your template, the form would be something like:

<form action="{% url 'name_of_your_url_to_get_to_view_method' %}" method="POST">
    {% csrf_token %}
        {{ form }} 
    <button type="submit">BUTTON</button>
</form>

and view.py would be something like this:

def yourViewMethod(request):
    if(request.method == "POST"):
        form = SegmentcliApiSerializer(request.POST)
        if(form.is_valid()):
            form.save()
            savedId = request.POST.get("request_id")
            return render(request, "yourFolder/yourHtmlFile.html", {"savedId": savedId})
    else:
        form = SegmentcliApiSerializer()
    return render(request, "yourFolder/yourHtmlFile.html", {"form": form})

and then, in whatever yourHtmlFile.html is, you can use

{{ savedId }}

somewhere to display it. I think that's what you're asking.

EDIT: Fixed so it got the value correctly.

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
marsonfire
  • 21
  • 4
  • I don't know if what I'm talking about is what you're thinking, but what I intended the process to be was something automated, not really putting anything on an HTML file. Instead, I wanted the API to return a simple text or JSON message to the client (like an ACK message). I could still do it with what you suggested I guess, since I would only have to parse the HTML and find the ID in the formatted text, but I think it could be simpler than that. – Philippe Fanaro Jul 17 '19 at 18:34
  • I haven't done anything with Django and JSON so I wouldn't be able to help much, but I think [this](https://docs.djangoproject.com/en/2.2/topics/serialization/#serialization-formats-json) and [this](https://stackoverflow.com/questions/2428092/creating-a-json-response-using-django-and-python) may help @PhilippeFanaro – marsonfire Jul 17 '19 at 18:44
  • The way I have been able to circumvent the problem so far is `curl -i -d "database=caedu5" http://localhost:8000/segmentcli_api/v1/`, and then use redirection (e.g. `> tmp/log.txt`) and parse the log file for the ID of the POST. If I could run something like that every time a new item is created in the DB, then that would be perfect. – Philippe Fanaro Jul 17 '19 at 19:23
1

I can't comment cause I don't have enough reputation but, with respect to @marsonfire's answer, if you want to have only simple JSON response you can use JsonResponse instead of render.

So, you'd have something like return JsonResponse({"savedId": savedId})

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
kebie
  • 485
  • 5
  • 16
1

In your views.py, more specifically, in the CreateApiView or ListCreateApiView classes, you can override the create method such that you can get a specific response from post request.

The create method comes from the CreateModelMixin class, which is inherited by the ListCreateAPIView, and which is in turn inherited by your specific Django model.

So follow the steps below:

from rest_framework import status
from rest_framework.response import Response

class SegmentcliApiList(generics.ListCreateAPIView):

    queryset = SegmentcliApi.objects.all() 
    serializer_class = SegmentcliApiSerializer 

    def create(self, request, *args, **kwargs):

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        # Original Response (inside the `CreateModelMixin` class)
        # return Response(
        #     serializer.data, 
        #     status=status.HTTP_201_CREATED, 
        #     headers=headers
        # )

        # We will replace the original response with this line 
        return Response(
            {'id': serializer.data.get('request_id')},
            status=status.HTTP_201_CREATED, 
            headers=headers
        )
        # serailizer.data is the created object in a JSON format 

This works for me. If it is not working for you, tell me what you're getting in comments. If it works for you, please accept the answer.

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
  • 1
    Nice content. Now I finally understand (more or less) how things are being inherited in the Django classes. By the way, is there an UML fluxogram of the class inheritance for the Django library, it would really help. If it doesn't exist, they should generate one, it can even be automated. – Philippe Fanaro Jul 18 '19 at 12:05
  • I am using the structure tap on pycharm it makes my job easy , never searched for uml class diagram for django rest btw thanks for the accept and the upvote and also for edit it looks better now – Mohamed Abd El-hameed Jul 18 '19 at 13:00
  • If you found a uml for restframework add it here in comments or edit the answer , It will be useful – Mohamed Abd El-hameed Jul 18 '19 at 13:08
  • You're welcome. I couldn't find any good UML charts for Django so far. I'm using something similar to you, though in VS Code. I right-click on a class and then choose `Go to definition`, and then VS Code opens a the reference source code with the specific item. – Philippe Fanaro Jul 18 '19 at 14:20
  • 1
    @PhilippeFanaro http://www.cdrf.co/ i think this link will be useful , as you asked for any UML ..... – Mohamed Abd El-hameed Nov 14 '19 at 08:48