I am learning DRF now, im little puzzuled by this many = True code. What does it do? Or what does it mean?
example 1
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.RelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
example 2
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
def list(self, request):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
I think you are confusing many=True with many to many realtionship, but the concepts is not like that
by setting many=True you tell drf that queryset contains mutiple items (a list of items) so drf needs to serialize each item with serializer class (and serializer.data will be a list)
if you don't set this argument it means queryset is a single instance and serializer.data will be a single object)
Related
I don't think I am implementing this correctly, but I am trying to change the serializer used for a queryset based on a condition (if there are no venues in one queryset, switch to another serializer and just return list object). I'm not quite sure how to do this.
Here is the view
class SavedVenuesViewSet(viewsets.ModelViewSet):
serializer_class = UserVenueSerializer
def get_queryset(self):
list_id = self.request.GET.get('list_id', None)
user = self.request.user.id
print(user)
print(list_id)
print(type(list_id))
qs = UserVenue.objects.filter(user_list=int(float(list_id)))
if not qs:
print("EMPTY LIST") #this is where i try to switch serializer
serializer_class = UserListSerializer
return UserVenue.objects.filter(id=int(float(list_id)))
else:
return qs
Here are the relevant serializers:
class UserVenueSerializer(serializers.ModelSerializer):
venue = mapCafesSerializer()
class Meta:
model = UserVenue
fields = ['user', 'user_list', 'venue']
depth = 2
[...]
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = UserList
fields = ['id', 'user', 'list_name']
depth = 2
The traceback isn't throwing an error but it isn't doing what I am hoping:
1
45
<class 'str'>
EMPTY LIST
[29/Sep/2021 11:05:36] "GET /api/savedvenues/?list_id=45 HTTP/1.1" 200 2
This is the correct practice to change serializer class in ModelViewSet:
You have to override get_serializesr_class method:
class SavedVenuesViewSet(viewsets.ModelViewSet):
serializer_class = UserVenueSerializer
def get_serializer_class(self):
if not self.get_queryset(): # Check your conditions here
return UserListSerializer
else:
return UserVenueSerializer
You could remove serializer_class field from your view, and create get_serializer_class() method, that will contain the logic for choosing the serializer. Is the best practice.
But, you can also, do it in your get queryset.
First, remove serializer_class attribute from your view. Instead, set it inside your get_queryset method (with this.serializer_class);
def get_queryset(self):
list_id = self.request.GET.get('list_id', None)
qs = UserVenue.objects.filter(user_list=int(float(list_id)))
if not qs:
self.serializer_class = UserVenueSerializer
return UserVenue.objects.filter(id=int(float(list_id)))
else:
self.serializer_class = UserListSerializer
return qs
Don't forget use the self.serializer_class.
I have a serializer that is meant to act as a template for other ModelSerializers.
class CountryBasedModelSerializer(ModelSerializer):
def __init__(self, data, context):
assert 'country' in self.Meta.fields
class Meta:
model = Country
fields = ()
I want to use it with this, which is the actual serializer which will be called.
class CountryBasedProjectSerializer(CountryBasedModelSerializer):
class Meta:
model = Project
fields = ('id', 'country', 'name')
I want to use it with this inherited viewset:
class CountryBasedViewset(viewsets.ModelViewSet):
queryset = None
serializer_class = CountryBasedModelSerializer
def get_queryset(self):
return self.queryset.filter(country_pk=self.request.data["country"])
And this is the actual viewset that will be called:
class CountryProjectBasedViewset(CountryBasedViewset):
queryset = Project.objects.all()
Is there anything that I am clearly doing incorrectly?
Just define the serializer_class for CounteryProjectBasedViewSet as below
class CountryProjectBasedViewset(CountryBasedViewset):
queryset = Project.objects.all()
serializer_class = CountryBasedProjectSerializer
I would like to create a route that returns some model properties as a JSON with the Django REST framework and filter them based on some properties. But I don't get the serializer to working properly.
class MaxQuantPathSerializer(serializers.ModelSerializer):
class Meta():
model = MaxQuantRun
fields = '__all__'
depth=0
class MaxQuantPathsAPI(generics.ListAPIView):
filter_fields = ['project', 'setup']
filter_backends = [DjangoFilterBackend]
def get(self, request, format=None):
get_data = request.query_params
queryset = MaxQuantRun.objects.filter(project=get_data['project'])
serializer = MaxQuantPathSerializer(queryset, many=True)
data = serializer.data
return JsonResponse(data, status=201, safe=False)
The queryset returns some values but the serializer returns an empty dictionary.
I updated the code based on the comments below. Now, a json file is returned.
I've been using select_related() to speed up a large DRF call with great success, but I've hit a wall.
My main serializer references two other serializers, and one of those references yet another serializer. I'm unsure as how to implement prefetching in the second level serializer.
serializer.py
class DocumentsThinSerializer(serializers.ModelSerializer):
class Meta:
model = Documents
fields = ('confirmed', )
class PersonThinSerializer(serializers.ModelSerializer):
documents = DocumentsThinSerializer()
class Meta:
model = Person
fields = ('name', 'age', 'gender')
class EventThinSerializer(serializers.ModelSerializer):
day = DayThinSerializer()
person = PersonThinSerializer()
#staticmethod
def setup_eager_loading(queryset):
return queryset.select_related('day', 'person')
class Meta:
model = Event
views.py
class EventList(generics.ListAPIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
queryset = Event.objects.all()
serializer_class = EventThinSerializer
def get_queryset(self):
return self.get_serializer_class().setup_eager_loading(queryset)
As you can see, I'm using the static method setup_eager_loading() to get things going, but I can't find a queryset hook for my PersonThinSerializer() to get the speedup when accessing the DocumentsThinSerializer() in the same way.
Assuming Documents has a foreign key to Person, you should be able to add "person__documents" to your queryset.select_related in EventThinSerializer.setup_eager_loading:
class EventThinSerializer(serializers.ModelSerializer):
day = DayThinSerializer()
person = PersonThinSerializer()
#staticmethod
def setup_eager_loading(queryset):
return queryset.select_related('day', 'person', 'person__documents')
I am working on project using django rest framework in which i have to filter different parameters given by user.I am using django Filter backend.
Here is my code:
class FilterViewSet(viewsets.ModelViewSet):
serializer_class = SearchSerializer
#Filters on specific fields
filter_backends = (DjangoFilterBackend,)
filter_fields = ('property_zipcode','property_state',
'property_county',
'property_city','property_area',)#range between 100 to 500 or area less then 500.
#range is pass by user as a property_area=300.
def filter_queryset(self, queryset):
if self.request.query_params.get('property_state', None):
queryset = super(FilterViewSet, self).filter_queryset(self.get_queryset())
return queryset
else:
queryset = self.get_queryset()
return queryset
Everything is working fine. But now i have to filter property_area based on range like 100 sqft to 500 sqft. How i can achieve this using djangoFilter backend?
Thanks #Gabriel Muj. From the django-filter documentation i solved my problem. I created my own filter class added fields which is use for filters.
class Filter(django_filters.FilterSet):
class Meta:
model = Property
fields = {
'property_state': ['exact'],
'year_built': ['lt', 'gt'],
'tax':['lt','gt'],
}
Call it in Viewset:
class FilterViewSet(viewsets.ModelViewSet):
serializer_class = SearchSerializer
#Filters on specific fields
filter_class = Filter
def filter_queryset(self, queryset):
if self.request.query_params.get('property_state', None):
queryset = super(FilterViewSet, self).filter_queryset(self.get_queryset())
return queryset
else:
queryset = self.get_queryset()
return queryset