I'd like to post to my Django server using POST so I can add a employee item.
views.py
class EmployeeList(generics.ListAPIView):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializer
class EmployeeDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializer
models.py
class Employee(models.Model):
firstname=models.CharField(max_length=10)
lastname=models.CharField(max_length=10)
emp_id=models.IntegerField()
def __str__(self):
return self.firstname;
serializer.py
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model=Employee
# fields={'firstname','lastname'}
fields='__all__'
My POST request:
{
"id": 8,
"firstname": "zxcvb",
"lastname": "bnmmm",
"emp_id": 3
}
Error I got:
{
"detail": "Method \"POST\" not allowed."
}
Even after using generics.RetrieveUpdateDestroyAPIView I can't POST, PUT or DELETE.
PS: I’m new to Django REST framework.
To provide a post method handler you'll need a view with a create() action (CreateAPIView or ListCreateAPIView). Check the documention about concrete view classes.
Change your EmployeeList view to inherit from ListCreateAPIView for add read-write endpoints to represent a collection of employees
class EmployeeList(generics.ListCreateAPIView):
queryset = Employee.objects.all()
serializer_class = EmployeeSerializer
Now, just register the views with the URL conf as usual
urlpatterns = [
path('employees/', EmployeeList, name='employee-list'),
path('employees/<int:pk>/', EmployeeDetail, name='employee-detail'),
]
Concrete view classes map methods defined in mixins such ListModelMixin, CreateModelMixin, RetrieveModelMixin, etc. to HTTP methods. By defaults, theese actions (see here) are mapped to the following HTTP methods
list - get
create - post
retrieve - get
update - put
partial_update - patch
destroy - delete
Related
I'm attempting to update a model that has more fields than what I want to pass to it. I've read the DRF documentation and I'm not finding the right approach. I came across using the UpdateModelMixin but I cannot seem to find a way to implement it successfully.
I've taken a few approaches so far, including using APIView in addition to the methods seen below.
Ultimately, I wish to pass the following to my view and have it update just the "order" field in my model. My model has many fields.
[
{
"id": "1",
"order": "5"
},
{
"id": "2",
"order": "3"
}
]
This is my view:
class WaitlistListGen(generics.ListCreateAPIView):
queryset = Waitlist.objects.all()
serializer_class = WaitlistSerializer
class WaitlistDetailGen(RetrieveUpdateDestroyAPIView):
queryset = Waitlist.objects.all()
serializer_class = WaitlistSerializer
And, this is my serializer:
class WaitlistSerializer(serializers.ModelSerializer):
class Meta:
model = Waitlist
fields = '__all__'
I finally figured it out and believe this is the best approach--I'll take feedback if it's not. I had to create a new view, extend the put method, and iterate over the data. I used the existing WaitlistSerializer:
class WaitlistUpdateGen(generics.UpdateAPIView):
serializer_class = WaitlistSerializer
def put(self, request):
waitlist_data = request.data
for waitlist_item in waitlist_data:
try:
waitlist = Waitlist.objects.get(id=waitlist_item['id'])
except Waitlist.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = self.serializer_class(
waitlist, data=waitlist_item, partial=True)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_200_OK)
class ABC(generics.ListCreateApiView):
#swagger_auto_schema(
operation_description="THIS API IS TO CREATE MESSAGES IN A LIST ",
auto_schema=AcceptFormDataSchema,
request_body=MessageGetSerializer
)
def get_queryset(self):
data =self.request.GET.get("code")
...
#swagger_auto_schema(
operation_description="THIS API IS TO CREATE MESSAGES IN A LIST ",
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=["data"],
properties={
"code": openapi.Schema(type=openapi.TYPE_STRING),
},
)
)
def post(self, request):
brand_code = request.data.get("code")
...
#serializer.py
class MessageSerializer(serializers.ModelSerializer):
class Meta:
model = Messages
fields = ("message_id", "content", "description")
My post method is working fine with the fields which I required using the same serializer but it's not working for the get_queryset method. Can anyone please suggest something on how I will get the fields using drf-yasg?
You shouldn't decorate get_queryset as that is an internal function and not part of the ApiView's endpoints. You probably see a get request in swagger because the ListCreateApiView you're using defines handlers for get and post methods.
Since you're not overriding the get method handler, you can inject a decorator into the ApiView's get method using Django's method_decorator, as indicated in drf-yasg section on swagger_auto_schema decorator.
The following is an example implementation to your ApiView that should also document the get endpoint.
#method_decorator(
name='get',
decorator=swagger_auto_schema(
operation_description="description from swagger_auto_schema via method_decorator"
)
)
class ABC(generics.ListCreateApiView):
serializer_class = MessageSerializer
def get_queryset(self):
data =self.request.GET.get("code")
...
#swagger_auto_schema(
operation_description="THIS API IS TO CREATE MESSAGES IN A LIST ",
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=["data"],
properties={
"code": openapi.Schema(type=openapi.TYPE_STRING),
},
)
)
def post(self, request):
brand_code = request.data.get("code")
...
--------------
#serializer.py
class MessageSerializer(serializers.ModelSerializer):
class Meta:
model = Messages
fields = ("message_id", "content", "description")
I want to update multiple instances of my models. I can currently update them one by one just fine.
I want to be able to update them with a PUT request to my URL:
www.my-api.com/v1/mymodels/
with the request data like so:
[ { "mymodel_id": "id1", "name": "foo"}, { "mymodel_id": "id2", "alert_name": "bar"} ]
If I try it this way now, I receive the following Django error:
Serializers with many=True do not support multiple update by default, only multiple create.
For updates it is unclear how to deal with insertions and deletions.
If you need to support multiple update, use a `ListSerializer` class and override `.update()` so you can specify the behavior exactly.
My model has a Serializer class MyModelSerializer
class MyModelSerializer(ModelSerializerWithFields):
class Meta:
model = MyModel
fields = "__all__"
def to_representation(self, instance):
data = super().to_representation(instance)
if instance.name is None:
del data['name']
return data
ModelSerializerWithFields extends serializers.ModelSerializer.
The View for MyModel is very basic:
class MyModelViewSet(MultipleDBModelViewSet):
serializer_class = MyModelSerializer
queryset = MyModel.objects.none()
MultipleDBModelViewSet extends BulkModelViewSet, and contains
def filter_queryset(self, queryset):
ids = self.request.query_params.get("ids", None)
if ids:
return queryset.filter(pk__in=json.loads(ids))
# returns normal query set if no param
return queryset
At which level do I need to use the ListSerializer class? ie: in ModelSerializerWithFields or in MyModelSerializer? Or somewhere else completely?
If anyone has any examples of this implementation, I'd be very grateful
Serializer Must be inherited from BulkSerializerMixin
So the serializer code will be like
from rest_framework_bulk.serializers import BulkListSerializer, BulkSerializerMixin
class SimpleSerializer(BulkSerializerMixin,
ModelSerializer):
class Meta(object):
model = SimpleModel
# only required in DRF3
list_serializer_class = BulkListSerializer
At Viewset don't forget to use the
filter_queryset method.
So your view will be like
class MyModelViewSet(MultipleDBModelViewSet):
serializer_class = MyModelSerializer
queryset = MyModel.objects.none()
def filter_queryset(self, queryset):
return queryset.filter(<some_filtering>)
I am getting error while updating. When i add data it is added successfully. This error is only comming for UpdateAPIView
{
"detail": "Method \"POST\" not allowed."
}
urls.py
path('groups/update/<int:pk>', views.GroupsUpdateAPIView.as_view(), name='api_groups_update'),
Views.py
class GroupsUpdateAPIView(generics.UpdateAPIView):
queryset = Groups.objects.all()
serializer_class = GroupsAddSerialzer
permission_classes = [UserIsAuthenticated]
def perform_update(self, serializer):
serializer.save(
group_updated_by = self.request.auth.application.user,
)
Serializer.py
class GroupsAddSerialzer(serializers.ModelSerializer):
class Meta:
model = Groups
fields = ['group_name', 'group_description', 'group_status']
The UpdateAPIView view uses the HTTP methods PUT and PATCH. The method POST is used to create a new instance with CreateAPIView view.
I'm trying to use the dehydrate method to generate my thumbnail like so:
class PostResource(ModelResource):
user = fields.ForeignKey(UserResource, 'user')
class Meta:
queryset = Post.objects.all()
resource_name = 'post'
authentication = Authentication()
authorization = DjangoAuthorization()
filtering = {
'published': ALL,
'type': ALL,
}
ordering = [
'hot_score',
'likes',
'date_created',
]
def dehydrate(self, bundle):
bundle.data['thumb'] = get_thumbnailer(self.image1, "image.jpg").get_thumbnail({'size': (95, 95),}).url
return bundle
What I get back is this error: "'FileField' object has no attribute 'closed'"
Am I getting this because self.image1 isn't a "real" FileField object (its a tastypie.fields.FileField which doesn't seem to be based off Django's FileField) so it doesn't have all the usual methods that easy-thumbnails needs? And if so, is there a solution?
If the solution is to use sorl-thumbnail instead, I will understand :) Thank you for any help provided!
Converted comment:
Get the image from the Django model rather than from the resource:
get_thumbnailer(bundle.obj.image1, "image.jpg").get_thumbnail({'size': (95, 95),}).url