7

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?

whoisearth
  • 4,080
  • 13
  • 62
  • 130

3 Answers3

4

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.

Carlos Calla
  • 6,556
  • 2
  • 16
  • 23
  • Thanks for this but it seems to still be forcing on the default DB not sure why. – whoisearth Sep 06 '14 at 23:55
  • 1
    I solved the problem with Django-Database-Routers. [Django - Using routers](https://docs.djangoproject.com/en/1.11/topics/db/multi-db/#using-routers) – elim Jun 02 '17 at 09:12
3

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

KenBuckley
  • 573
  • 6
  • 13
0

Say for example you're using a ListCreateAPIView

You might might be able to do it at the view level, using get_queryset

class YourModelDRFGetView(generics.ListCreateAPIView):
    serializer_class = YourModelDRFViewSerializer

    def get_queryset(self):
        return YourModel.objects.using('your_read_replica').all()

Where your_read_replica is defined in settings.py:

replica_database_url = os.environ.get("DATABASE_REPLICA_URL") or database_url
DATABASES["your_read_replica"] = dj_database_url.parse(replica_database_url)
jmunsch
  • 22,771
  • 11
  • 93
  • 114