What is the meaning in single model instance in RetrieveAPIView in drf - django-rest-framework

What is the meaning of single model instance in RetrieveAPIView in Django REST framework.And how can we use? And will it look?

As my understanding:
single model instance: Example we use RetrieveAPIView. If we read the method that handle requests to that class, that is:
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
We can see self.get_object(), it will build a Queryset to get object instance from our model class using method get(), or rather using get_object_or_404(). As we know, get() will only take 1 object instance, or it called single model instance.
Example Book.objects.get(id=10).
For more detail, we can open this link. Start from def retrieve then read also get_object().
Likewise on DestroyAPIView and UpdateAPIView.
collection of model instances: When build a Queryset, it using all() or filter(), according to what we wrote in queryset = .... or we override in def get_queryset. Example: Book.objects.all(). See this link and read def list.
CMIW.

Related

Accessing ViewSet object list to provide extra context to serializer

I am attempting to add context to a serializer within a ModelViewSet which is dependent on the current paged object list in context. I'll explain with an example.
I am building a viewsets.ModelViewSet that lists Users and a list of favorite_foods. However- the list of user's favorite foods in some external microservice accessible via API. Building a ViewSet to collect objects and performing HTTP requests on each is trivial, we can do something like this:
class UserViewSet(viewsets.ViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserSerializer(serializers.ModelSerializer):
favorite_foods = serializers.SerializerMethodField()
def get_favorite_foods(self, instance):
# performs an HTTP call and returns a list[] of foods.
return evil_coupled_microservice_client.get_user_food_list(instance)
class Meta:
model = User
fields = ('id', 'name', 'favorite_foods')
The issue is (aside from some ugly infrastructure coupling) this is going to make an HTTP request count equivalent to the page size. Instead- it would be great if I could prefetch the favorite food lists for all users on the page in a single HTTP call, and just add them into context, like this:
class UserViewSet(viewsets.ViewSet):
def get_serializer_context(self):
context = super().get_serializer_context()
users = <-- This is where I want to know what users are in the current filtered, paginated response.
users_food_dict = evil_coupled_microservice_client.get_many_users_food_list(users)
context.update({'usesr_foods': users_food_dict})
return context
However- it doesn't appear there is any way to fetch the object list that's going to be serialized. Although (I'm fairly sure) get_serializer_context is called after the queryset is filtered and paginated, I'm not sure how to access it without doing some really hacking re-compiling of the queryset based on the query_params and other pieces attached to the class.
I'll post my current solution. It's not terrible, but I'm still hoping for a cleaner built-in.
class UserViewSet(viewsets.ViewSet):
...
def list(self, request, *args, **kwargs):
# Overrwite `ListModelMixin` and store current set
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
self.current_queryset = page
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
self.current_queryset = queryset
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
This is untested so far (not sure about functionality on Detail endpoints for instance) allows for the current_queryset to be fetched within the serializer context.

get_queryset is executed and not get_object

I am trying to use get_object to retrieve a single object from my database. However, my code always enters into get_queryset and not get_object so I always return a list of objects.
Here is my viewset :
class DiagramView(viewsets.ModelViewSet):
queryset = Diagram.objects.all()
serializer_class = DiagramSerializer
pk_url_kwarg = 'id'
def get_object(self, *args, **kwargs):
return self.queryset.get(id=kwargs.get('id'))
def get_queryset(self):
print('im here')
My route is :
router.register('api/diagramsingle', DiagramView, 'diagramsingle')
And I access this route like this :
api/diagramsingle/?id=1
Thank you for your answer.
As is written in the documentation on routers, for a SimpleRouter, the detail view has as pattern api/diagramsingle/<int:pk>/, so you access a single object with:
api/diagramsingle/1/
where you specify the primary key in the path, not in the querystring.

How to use a custom id with Graphene and Relay?

I've implemented graphql and I'm migrating to relay. I already have a uuid for every table and that is named 'id'. And my application I found this github thread that talks about possibly changing the spec but it feels like a rabbit hole.
Is there a simple way that I can use my own custom id with relay?
If you've already implemented a default relay endpoint then you should have some
TableNameNode classes that have a Meta nested class, and a seperate Query
class.
class ExampleTableNameNode(DjangoObjectType):
class Meta:
model = ExampleTableName
interface = (relay.Node,)
class Query(object):
example_table_name = relay.Node.Field(ExampleTableNameNode)
all_example_table_names = DjangoFilterConnectionField(ExampleTableNameNode)
def resolve_example_table_name(self, info, **kwargs):
pass
def resolve_all_example_table_names(self, info, **kwargs):
pass
The interface = (relay.Node,) is what defines:
How the ids are being generated
How they are used to fetch data
If we create a relay.Node subclass that redefines these two features then we can use our custom ids.
class CustomNode(relay.Node):
class Meta:
name = 'Node'
#staticmethod
def to_global_id(type, id):
#returns a non-encoded ID
return id
#staticmethod
def get_node_from_global_id(info, global_id, only_type=None):
model = getattr(Query,info.field_name).field_type._meta.model
return model.objects.get(id=global_id)
Here we implemented two functions, to_global_id, and get_node_from_global_id.
The line model = ... is a bit of magic to go from the graphql query table name
to the actual model. If that doesn't work you'll just need to make a dictionary
to go from something like example_table_name to the actual ExampleTableName
django model.
Once you do that you'll have to replace the two references to relay.Node with
CustomNode like so.
class ExampleTableNameNode(DjangoObjectType):
class Meta:
model = ExampleTableName
interface = (CustomNode,)
class Query(object):
example_table_name = CustomNode.Field(ExampleTableNameNode)
all_example_table_names = DjangoFilterConnectionField(ExampleTableNameNode)
def resolve_example_table_name(self, info, **kwargs):
pass
def resolve_all_example_table_names(self, info, **kwargs):
pass
The answer is in the graphene docs. I read them when I was implementing
graphene and relay but there is so much to learn at once that it's easy to read
through custom node section and not remember later that you need to do a custom
node solution.

Which part of script makes JSON API return as array of objects in Django Rest Framework?

I implemented JSON API using ListAPIView. I just wonder which part of script makes JSON API to return as array of objects like below.
Can anyone point out and where should I change if I want to return just object?
Views.py
class summaryData(generics.ListAPIView):
serializer_class=summarySerializer
def get_queryset(self):
pk=self.kwargs['pk']
key=self.kwargs['keyword']
return summary.objects.filter(html__pk=pk).filter(keyword=key)
serializer.py
class strToJson(serializers.CharField):
def to_representation(self,value):
x=JSON.loads(value)
return x
class summarySerializer(serializers.ModelSerializer):
project=serializers.CharField(read_only=True,source="html.project")
version = serializers.CharField(read_only=True, source="html.version")
json = strToJson()
class Meta:
model=summary
fields=('project','version','json')
Because you want to get a single object, you want to use a RetrieveAPIView (or a variant). This would correspond to the "summary detail" url (as opposed to the "summary list" url, where ListAPIView makes sense). This is what it should roughly look like:
path-to-your/urls.py:
urlpatterns = [
...
url(r'^summaries/(?P<pk>[0-9]+)/$', views.SummaryDetail.as_view()),
]
path-to-your/views.py:
class SummaryDetail(generics.RetrieveAPIView):
queryset = Summary.objects.all()
serializer_class = summarySerializer
you are using generics.ListAPIView this means your intention is to get list of all objects so generics.ListAPIView gives array of objects. check this blog for ref

get_queryset method and ViewSets in django rest framework

I am doing exactly as the example states
here is my method
class FeedViewSet(viewsets.ModelViewSet):
model = Feed
serializer_class = FullFeedSerializer
def get_queryset(self):
user = request.user
queryset = Feed.objects.get_nearby(user)
return queryset
when i execute it, it says request not defined .. which actually isn't. the example at the rest framework's site also haven't defined request. what am i doing wrong?
The request object is available (on either REST framework's class based views, or Django's standard class based views) as self.request. You're missing the self. part of that.

Resources