6

Hi there I want to create a custom method in a modelviewset which needs to perform a save and an update logic in a single post request.

Here is my breeding.viewsets.py

class BreedingViewSet(viewsets.ModelViewSet):
    queryset = Breeding.objects.all()
    serializer_class = BreedingSerializer

Since the above method has a higher level of abstraction and is actually providing or performing automatic CRUD functions.

Now the problem here is i dont have any control for a multiple queries like saving an object and updating another object in a single post request.

e.g

def save_and_update(self, request):
     // do save an object here.
     // do update an object here.

How can we achieve such powerful functionalities? Did i missed something? I found this documentation but i dont know how to implement the given instruction.

UPDATE

This is what im looking for How do I create multiple model instances with Django Rest Framework?

But the answer can only save a multiple instances in a single post request of that same model. But Im hoping also that we can perform queries for a different models in that single function.

Community
  • 1
  • 1
Shift 'n Tab
  • 8,808
  • 12
  • 73
  • 117
  • I am not sure what you are having a problem with. You seem to want to override the default behavior of the model viewset, but I am not sure what behavior you have a problem with. You can override POST method handling by defining create() in your viewset. You can override PUT method handling by defining update() in the viewset. You can also define create() and update() in your serializer. What is it that you actually want to do? – Mad Wombat Dec 06 '16 at 17:03
  • @MadWombat to clarify my question. I need to add an object and update another object with a single post request using modelviewset. I want to define a single function like `create()` that adds a data and update another data. hope i explained it well. – Shift 'n Tab Dec 06 '16 at 17:51
  • The right solution depends on your actual problem. And I still don't know what it is. Are you creating multiple objects of the same type? Are they the same type as your viewset model? Are they nested? Are they related at all? – Mad Wombat Dec 06 '16 at 19:01
  • The other object i am about to update is not the same as my viewset model that is my real problem. and i am only creating one object which is the viewset model `Breeding` and would like to update another model at the same time too but i dont have any knowledge how to do it. – Shift 'n Tab Dec 06 '16 at 19:08
  • Well, what prevents you from defining create() method in your viewset and updating/creating whatever you want in there? – Mad Wombat Dec 06 '16 at 19:18

2 Answers2

13

Well, from the comments, it looks like you want to update some unrelated model when you create your breeding model. This should be easy.

class BreedingViewSet(viewsets.ModelViewSet):
    queryset = Breeding.objects.all()
    serializer_class = BreedingSerializer

    def create(self, request):
        # do your thing here
        return super().create(request)
Mad Wombat
  • 14,490
  • 14
  • 73
  • 109
  • 1
    One question again sir, how can i get the specific data from the request? supposed we provide data that looks like this `{ id: '1', heat: '2' }`. How can i get the heat from the request sir? – Shift 'n Tab Dec 06 '16 at 19:26
  • `request.data` will contain the data you send – Mad Wombat Dec 06 '16 at 19:37
  • 1
    so `request.data['heat']` would contain the heat – Mad Wombat Dec 06 '16 at 19:38
  • 1
    Mind you that your breeding model will not get created until the very end. If you need to reference it in some way, you might want a different solution. – Mad Wombat Dec 06 '16 at 19:39
  • 1
    that it means that when error happens the creation of breeding might fail? – Shift 'n Tab Dec 06 '16 at 19:40
  • Well, yes. And your API call will return a 500 server error. So you might want to be careful and think about how you want your API to behave if errors occur. – Mad Wombat Dec 06 '16 at 21:23
  • If, for example, you want your API to create the breeding model and return a success status code no matter what, you can enclose everything else in a try: except: – Mad Wombat Dec 06 '16 at 21:24
  • Is it ok to this in create or is `perform_create` a better place to do it. And can I wrap this method in a `transaction.atomic`? – Vaibhav Vishal Aug 22 '19 at 10:39
  • 1
    @VaibhavVishal depends on what you are trying to do. create() gets a request object as an argument, but perform_create() gets a serializer. Thats the difference. – Mad Wombat Aug 22 '19 at 16:38
  • I can access request anytime using `self.request` – Vaibhav Vishal Aug 22 '19 at 19:57
2

Use this to create or update using POST

class BreedingViewSet(viewsets.ModelViewSet):
    queryset = Breeding.objects.all()
    serializer_class = BreedingSerializer


    def get_object(self):
        if self.action == 'create':
            queryset = self.filter_queryset(self.get_queryset())
            filter_kwargs = {self.lookup_field: self.request.data.get('id')}
            obj = get_object(queryset, **filter_kwargs)
            self.check_object_permissions(self.request, obj)
            return obj
        else:
            return super(BreedingViewSet, self).get_object()

    def create(self, request, *args, **kwargs):
        if request.data.get('id'):
            return super(BreedingViewSet, self).update(request, *args, **kwargs)
        else:
            return super(BreedingViewSet, self).create(request, *args, **kwargs)
Vaibhav Jain
  • 5,287
  • 10
  • 54
  • 114