Cannot POST using Rest API - python

So I can retrieve my data perfectly fine but when I try to post I get
{"detail":"Method \"POST\" not allowed."}
views.py
class ClubFullList(generics.ListAPIView):
serializer_class = ClubSerializer
def get_queryset(self):
return Club.objects.all()
class ClubList(generics.ListAPIView):
serializer_class = ClubSerializer
def get_queryset(self):
username = self.kwargs['username']
return Club.objects.filter(abv=username)
models.py
class Club(models.Model):
name = models.CharField(max_length=255)
abv = models.CharField(max_length=255)
serializers.py
class ClubSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Club
fields = ['name', 'abv']
How can I solve this?

You are sending POST request on an endpoint which only allows GET request.
ListAPIView is a read-only generic view. To create model objects using POST request, use CreateAPIView or ListCreateAPIView.

From the docs for ListApiView:
Used for read-only endpoints to represent a collection of model instances.
If you want to post to your endpoint, you'll need to use a different view class.

Related

Serializing model queryset showing empty [OrderedDict()]

I am building a blog app with React and Django and I am serializing model's instances saved by particular user, First I am just trying to test with .all() then I am planning to filter by specific user But when I serialize queryset with Serializer like:
class BlogSerializerApiView(viewsets.ModelViewSet):
serializer_class = BlogSerializer
def get_queryset(self, *args, **kwargs):
queryset = Blog.objects.all()
output_serializer = BlogSerializer(queryset, many=True)
print(output_serializer.data)
return "Testing"
It is showing in console:
[OrderedDict(), OrderedDict()]
and when I access it like
print(output_serializer)
Then it is showing:
BlogSerializer(<QuerySet [<Blog: user_1 - Blog_title>, <Blog: user_2 - second_blog_title>]>, many=True):
serializer.py:
class BlogSerializer(serializers.Serializer):
class Meta:
model = Blog
fields = ['title']
models.py:
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=30, default='')
def __str__(self):
return f"{self.user} - {self.title}"
What I am trying to do:
I am trying to serialize queryset to show on page in react frontend, I will relate with specific user later.
I have tried many times by changing CBV serialization method by generics.ListAPIView instead of viewsets.ModelViewSet but still same thing.
There is a concept error here. The get_queryset function is not supposed to return serialized data. It must return a QuerySet of model objects.
To achieve what you want you can just do:
class BlogSerializerApiView(viewsets.ModelViewSet):
serializer_class = BlogSerializer
def get_queryset(self, *args, **kwargs):
return Blog.objects.all()
The Django Rest Framework will take care of serializing data.
In fact, you can even do it way more simple. Defining the view's queryset field like this:
class BlogSerializerApiView(viewsets.ModelViewSet):
queryset = Blog.objects.all()
serializer_class = BlogSerializer
Additional:
You said you will relate to current user later. You could achieve that in fact in the get_queryset method filtering aginst the user
class BlogSerializerApiView(viewsets.ModelViewSet):
serializer_class = BlogSerializer
def get_queryset(self, *args, **kwargs):
return Blog.objects.filter(user_id=USER_ID)
Hope this helps!
I was using
class BlogSerializer(serializers.Serializer):
.......
so it was showing empty results (no idea why, I think its deprecated)
After replaceing it with
class BlogSerializer(serializers.HyperlinkedModelSerializer):
It worked

How to request param inside ModelSerializer

I need to return some computed value using request param.
It seems that I need to get access to request param from inside ModelSerializer.
How can I do this?
class PostSerializer(serializers.ModelSerializer):
owner = UserSerializer()
spot = SpotSerializer()
is_login_user_favorite = serializers.SerializerMethodField()
class Meta:
model = Post
fields = '__all__'
read_only_fields = ('owner',)
def get_is_login_user_favorite(self, validated_date):
return True # I need change this dynamically
class PostListAPIView(generics.ListAPIView):
serializer_class = serializers.PostSerializer
queryset = Post.objects.all().order_by('-pk')
permission_classes = [IsAuthenticated]
You can access it through context. Like this:
class PostSerializer(serializers.ModelSerializer):
...
def get_is_login_user_favorite(self, validated_date):
request = self.context['request'] # <-- Here
....
return value # I need change this dynamically
Basically, request is sent to Serializer through context automatically when you are using Generic API Views. This is also explained in the methods section(at the bottom named as 'other methods') of documentation.

Django REST POST with PK to HyperlinkedModelSerializer, how to translate PK to URL?

I'm new to Django and Django REST. I have been creating a simple practice project.
Models:
class Locker(models.Model):
locker_owner = models.ForeignKey(User, related_name='lockers', on_delete=models.CASCADE)
locker_desc = models.CharField(max_length=100)
locker_rating = models.IntegerField(default=0)
Serializers:
class LockerSerializer(serializers.ModelSerializer):
locker_owner = serializers.HyperlinkedRelatedField(
view_name='user-detail',
lookup_field='id',
queryset=User.objects.all())
# how to add locker owner with id?
class Meta:
model = Locker
fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'id', 'username', 'email', 'groups')
Views:
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class LockerViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows lockers to be viewed or edited.
"""
# def create(self, request):
queryset = Locker.objects.all()
serializer_class = LockerSerializer
I use this to POST:
ttp -f POST localhost:8000/lockers/ locker_owner_id=2 locker_desc='desc of locker 3' locker_rating=150
But then the response is
"locker_owner": [
"This field is required."
]
Main Point:
I would like to create a new locker, and use User id as its locker_owner, yet still maintain the HyperlinkedModelSerializer. It won't let me, since they need url for locker_owner. Once I use hyperlink in the locker_owner of my POST request it works, but I don't know how to translate locker_owner=2 to it's url.
Any help would be appreciated. I have been looking for answers in days. Thank you!
This is not something you can do out-of-the-box. You will need to implement your own custom serializer Field, and override the to_representation method:
serializers.py
from rest_framework.reverse import reverse
class CustomRelatedField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
return reverse('<your-user-detail-view-name>', args=(value.pk,), request=self.context['request'])
class LockerSerializer(serializers.ModelSerializer):
locker_owner = CustomRelatedField(queryset=User.objects.all())
class Meta:
model = Locker
fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')
You can then simply POST a simple JSON to create a new Locker object:
{
"locker_owner": 2,
"locker_desc": 'desc of locker 3',
"locker_rating": 150
}
I have found the solution myself looking at the tutorials available. The other answers have not really answered the question fully.
For those wanting to get url of a foreign key to be saved, here, locker_owner, just get them using hyperlinked related field
In my serializer:
class LockerSerializer(serializers.HyperlinkedModelSerializer):
locker_owner=serializers.HyperlinkedRelatedField(
read_only=True,
view_name='user-detail')
class Meta:
model = Locker
fields = ('locker_desc', 'locker_rating', 'locker_owner')
I was trying to get the id in the lookup field, but actually the lookup field is searching the id from my url. That's why it could not find it. Simple and done. Thank you for all the answers.

'CityListViewSet' should either include a `serializer_class` attribute, or override the `get_serializer_class()` method

I am assuming by the error in the title, once more here for clarity
'CityListViewSet' should either include a `serializer_class` attribute,
or override the `get_serializer_class()` method.
that my serializer isn't connected to my view, which in my code it should be. I'm not really sure where the bug is in this one. I wonder if any of you have seen something similar?
Here is the code.
Router:
router.register(r'city-list', CityListViewSet, base_name='city-list')
view:
class CityListViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Venue.objects.values('city').distinct()
serializer = CitySerializer(queryset, many=True)
ordering_fields = ('city',)
ordering = ('city',)
serializer:
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields =('city',)
what is it that would be causing such an assertion error with the code seemly wired up correctly?
The exception says it itself. You need a serializer_class attribute. You have serializer.
Add this code snippet to your views.py file
class CityListViewSet(viewsets.ReadOnlyModelViewSet): # (viewsets.ModelViewSet)
serializer_class = CitySerializer
queryset = City.objects.values('city').distinct()
serializer = CitySerializer(queryset, many=True)
ordering_fields = ('city',)
ordering = ('city',)
error says you define a serializer attribute, you need to correct with writing
serializer_class attribute in your code,
serializer_class = yourCreatedSerializer
serializer = CitySerializer(queryset, many=True)
The above line should be replaced with
serializer_class = CitySerializer(queryset, many=True)
Here you used a different model name:
view:
class CityListViewSet(viewsets.ReadOnlyModelViewSet): #(viewsets.ModelViewSet)
queryset = City.objects.values('city').distinct()
serializer = CitySerializer(queryset, many=True)
ordering_fields = ('city',)
ordering = ('city',)
import -> from .serializers import TaskSerializers,CitySerializer
serializer:
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields =('city',)
i got this error when declared post method in view and trying to send post data without serialize, if you are doing the request from javascript i solved it using JSON.stringify()
you have to override the user just add
from django.contrib.auth.models import User
from rest_framework.permissions import IsAdminUser
and in createViewList
permission_classes = [IsAdminUser]
Rename this to
serializer = CitySerializer(queryset, many=True)
This
serializer_class = yourCreatedSerializer
Your job is done

Need help implementing a base serializer in DJango

I am trying to implement a base serializer and I am following the "http://www.django-rest-framework.org/api-guide/serializers/#baseserializer".
My urls.py:
url(r'^auth/myuser/(?P<pk>[0-9]+)/profile/$', UserProfileViewSet.as_view({'patch':'update'}), name='user-profile'),
Views.py:
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = UserProfileSerializer
def get(self,request,pk,*args,**kwargs):
user_instance = CustomUser.objects.get(pk=pk)
dashboard_data = UserProfileSerializer(user_instance)
content = {'result': dashboard_data}
return Response(content)
Serializers.py:
class UserProfileSerializer(serializers.BaseSerializer):
def to_representation(self,obj):
return{
'email':obj.email,
'first_name':obj.first_name,
'last_name':obj.last_name,
'date_of_birth':obj.date_of_birth,
'gender':obj.get_gender_display(),
'location':obj.location,
'calling_code':obj.callingcode,
'phone_primary':obj.phone_primary,
'phone_secondary':obj.phone_secondary,
'website':obj.website
}
But I am getting the error "User object is not JSON serializable", and I don't find any attributes of the User obj that are not serializable.
I already found some answers on SO, but I don't find any similar steps in the django rest framework api guide. So looking for a solution that is in sync with the api-guide.
Serializer:
It seems what you need is a ModelSerializer
The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields.
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = CustomerUser
fields = '__all__'
I have set fields attribute to __all__ to indicate that all the fields in the model are serialized. But, you can also specify which fields to include exaclty:
fields = ('email', 'first_name', 'last_name',) # etc.
ViewSet:
The second point is about the ModelViewSet where you don't really need to implement the get method because it is already implemented for you. You just need to declare the queryset and the serializer_class just like you have already done:
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = UserProfileSerializer
I guess you'll have to render the response in JSON format before returning it.
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = UserProfileSerializer
def get(self,request,pk,*args,**kwargs):
user_instance = CustomUser.objects.get(pk=pk)
dashboard_data = UserProfileSerializer(user_instance)
content = {'result': dashboard_data}
return JSONResponse(content, status=200)
You'll need following imports for this,
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
If this doesn't work just try passing dashboard_data to the JSONResponse function

Categories