Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django rest framework multiple database

I have a view that I'm using for GET and POST to a database that's NOT the default DB.

class DeployResourceFilterView(generics.ListAPIView):
    serializer_class = ResourceSerializer

    def get(self, request, format=None):
        resname = self.request.GET.get('name')
        queryset = Resmst.objects.db_manager('Admiral').filter(resmst_name=resname)
        serializer = ResourceSerializer(queryset)
        if queryset:
            return Response(serializer.data)
        else:
            raise Http404

    def post(self, request, format=None):
        serializer = ResourceSerializer(data=request.DATA, many=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

The GET works perfectly fine but on the POST it constantly fails complaining that the table does not exist. My assumption is that the reason for this is because it's trying to use the default database not the 'Admiral' one I have defined as my secondary database. How do I assign the POST to use a specific database and not the default?

like image 903
whoisearth Avatar asked Sep 05 '14 17:09

whoisearth


2 Answers

See this link to the docs: https://docs.djangoproject.com/en/1.7/topics/db/multi-db/#selecting-a-database-for-save

You can specify the database you want to save to, just pass it as a parameter:

my_object.save(using='database-name')

In your case it would be:

serializer.save(using='Admiral')

You should also use it in your queryset like this:

queryset = Resmst.objects.using('Admiral').filter(resmst_name=resname)

Since it is a queryset and not a command that needs a db_manager as creating objects is.

like image 107
Carlos Calla Avatar answered Sep 23 '22 03:09

Carlos Calla


In the code provide by the op, the issue arises when serializer is trying to be saved, i.e. on the line

serializer.save()

-the default database is being used. One cannot use the form serializer.save(using='database_name') as the accepted answer recommends, because the kwarg "using='database_name" will not be understood/expected by a serializer class (in this case the class ResourceSerializer).

The django docs state that if you have a model (model.Model) then yes you can save using my_object.save(using='database_name') see here for the quote: https://docs.djangoproject.com/en/2.1/topics/db/multi-db/#selecting-a-database-for-save . But serializer is obviously not a model instance.

In such a case as above, you could subclass (or amend -I prefer amending when I have created the serializer myself) ResourceSerializer and change the create and update methods to work utilizing db_manager('Admiral'). For example:

class MyResourceSerializer(ResourceSerializer):
    def create(self, validated_data):
        """
        copy the create from ResourceSerializer and amend it here, with code such as
        follows in the try section.
        """
        ModelClass=Resmst  # or whichever desired model you are acting on
        try:
            instance = ModelClass.objects.db_manager('Admiral').create(**validated_data)
        except TypeError: # or whatever error type you are mitigating against, if any
            raise TypeError()
        return instance

A nice alternative (as elim mentions in one of the comments to this question) is to add a router and have this all handled without having to insert "using" or "db_manager" throughout the code: https://docs.djangoproject.com/en/2.1/topics/db/multi-db/#using-routers

like image 41
KenBuckley Avatar answered Sep 21 '22 03:09

KenBuckley