#serializers.py
from rest_framework import serializers
class CommunitysStaffSerializer(serializers.ModelSerializer):
role = serializers.CharField(max_length=100,default='management')
community = serializers.PrimaryKeyRelatedField(read_only=True)
user = serializers.PrimaryKeyRelatedField(read_only=True)
#views.py
from rest_framework.response import Response
from admindashboard.serializers import CommunitysStaffSerializer
#api_view(['POST'])
def Communitystaff(request,pk=None):
if request.method == 'POST':
serializer = CommunitysStaffSerializer(data = request.data)
if serializer.is_valid():
Staff = CommunityStaff.objects.get(id = request.data['id'])
Staff.community=serializer.validated_data['community']
Staff.role=serializer.validated_data['role']
Staff.save()
return Response({'detail': 'entry successfully'})
else:
return Response({'error': 'unable to entry staff'}, status=status.HTTP_400_BAD_REQUEST)
else:
return Response (serializer.data)
#error
File "C:\Users\Pinakee.Somyadarshee\Desktop\mykommunity\admindashboard\urls.py", line 2, in
from admindashboard.views import Login_post,City_post,City_list,City_update,City_remove,Community_update,Community_list,Community_post,Community_detail,Admindash_list,Admindash_update,Admindash_remove,Admindash_post,Admindash_detail,Communitystaff
File "C:\Users\Pinakee.Somyadarshee\Desktop\mykommunity\admindashboard\views.py", line 11, in
from admindashboard.serializers import CommunitysStaffSerializer
ImportError: cannot import name 'CommunitysStaffSerializer' from 'admindashboard.serializers' (C:\Users\Pinakee.Somyadarshee\Desktop\mykommunity\admindashboard\serializers.py)
If serializers.py and views.py are in the same folder, use:
from .serializers import CommunitysStaffSerializer
Anyway, if you are using serializer.ModelSerailizer, you should define the model or, otherwise, you could use other serializer:
https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
Related
While I am calling Django url, I get an error:
AssertionError: .accepted_renderer not set on Response.
My code is:
from rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer
from myapp.models import employees
from .serializers import EmployeeSerializer
#api_view(('GET',))
#renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def getData(request):
employees = {'name':'Bill', 'location':'Kolkata' }
return Response(employees)
def getEmployees(request):
employee_list = employees.objects.all()
serializer = EmployeeSerializer(employee_list, many = True)
return Response(serializer.data)
It should not be any line spaces between #api_view decorators and the views getData and getEmployee should have its individual decorators too
#api_view(('GET',))
#renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def getData(request):
employees = {'name':'Bill', 'location':'Kolkata' }
return Response(employees)
#api_view(('GET',))
#renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def getEmployees(request):
employee_list = employees.objects.all()
serializer = EmployeeSerializer(employee_list, many = True)
return Response(serializer.data)
I want to create an endpoint, in this endpoint its possible to send POST request, if the POST request
is validated, then the page download a csv
I created the serializer form to make a easy validation of the data received
My problem is that the csv its easy downloaded in a HttpResponse, but i need neccesary to make a endpoint and a validation of the data in a post request.
My principal problem is that i can´t return the export function next of the validation
This are my files
#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^hello-view/', views.HelloApiView.as_view()),
]
Serializers
#serializers.py
from rest_framework import serializers
class HelloSerializer(serializers.Serializer):
"""Serializes a name field """
name = serializers.CharField(max_length=100)
seller_id = serializers.CharField(max_length=100)
def validate_name(self, dob):
UnitOfMeasureName = ["Each", "Grams", "Ounces", "Pounds", "Kilograms", "Metric Tons"]
if dob in UnitOfMeasureName:
return dob
else:
raise serializers.ValidationError('Wrong username')
And the views files
In this file i created the export function to try to export the csv data, but doesnt works
import csv
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import serializers
class HelloApiView(APIView):
def export(self, request):
response = HttpResponse(content_type='text/csv')
writer = csv.writer(response)
writer.writerow(['First name', 'Last name', 'ID'])
response['Content-Disposition'] = 'attachment; filename="one.csv"'
return response
serializer_class = serializers.HelloSerializer
def get(self, request, format=None):
an_apiview = [
'Uses HTTP METHOD as function',
'Its is similar to a traditional django view'
]
return Response({'message': 'Hello', 'anapi': an_apiview})
def post(self, request):
serializer = serializers.HelloSerializer(data = request.data)
if serializer.is_valid():
in this place i want to return the file
else:
return Response(
serializer.errors, status = status.HTTP_400_BAD_REQUEST)
Add a new endpoint to your urls.py file
#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^hello-view/', views.HelloApiView.as_view()),
url(r'^csv_download/$', views.csv_download, name="csv_download"),
]
Then in your views.py file, add a function called csv_download and move all of your stuff there (This might be unnecessary, but it sure makes for cleaner, more readable code)
# views.py
import csv
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import serializers
class HelloApiView(APIView):
def get(self, request, format=None):
an_apiview = [
'Uses HTTP METHOD as function',
'Its is similar to a traditional django view'
]
return Response({'message': 'Hello', 'anapi': an_apiview})
def csv_download(request):
if request.method == 'POST':
serializer_class = serializers.HelloSerializer
serializer = serializers.HelloSerializer(data = request.data)
if serializer.is_valid():
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="one.csv"'
writer = csv.writer(response,delimiter=',') # I always like to specify the delimeter
writer.writerow(['First name', 'Last name', 'ID'])
#Then you may actually want to write some data to the CSV file, currently, you've only defined the headers (first row). An example would be like:
for value in list_of_objects:
writer.writerow([
value.first_name,
value.last_name,
value.id
])
return response
else:
return Response(
serializer.errors, status = status.HTTP_400_BAD_REQUEST)
else:
# redirect them or do something here if they hit this URL without a POST request
I am trying to check and display user online status with django and django rest framework.
I have tried this article: Django - detect if user is online / offline
But did not work on APIview only works on views with render and Httpresponse.
Updated
Here is the code for the middleware class
import datetime
from django.core.cache import cache
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class ActiveUserMiddleware(MiddlewareMixin):
def process_request(self, request):
current_user = request.user
if request.user.is_authenticated:
now = datetime.datetime.now()
cache.set('seen_%s' % (current_user.username), now, settings.USER_LASTSEEN_TIMEOUT)
The APIView
class ProfilePersonal(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = UserProfileSerializer
def get(self):
try:
queryset = Account.objects.get()
except Account.DoesNotExist:
return Response(data={'non_field_errors': 'Request could not be validated.'},
status=status.HTTP_400_BAD_REQUEST)
serializer_data = self.serializer_class(queryset)
return Response(
data=serializer_data,
status=status.HTTP_200_OK
)
Here I have an endpoint to create media content for users. The endpoint works, but I have a feeling my design implementation is incorrect.
Should validation logic be contained in serializers create? Is this bad practice? I attempted to move validation logic to models.py, but ran into issues with accessing the model, specifically this line - self.model(user=user, category=category).
view.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import UserMedia
from .renderers import UserMediaSerializerJSONRenderer
from .serializers import UserMediaSerializer
class UserMediaCreateAPIView(APIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserMediaSerializerJSONRenderer,)
serializer_class = UserMediaSerializer
def post(self, request):
userMedia = request.data.get('userMedia', {})
serializer = self.serializer_class(data=userMedia)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user, category=userMedia['category'])
return Response(serializer.data, status=status.HTTP_201_CREATED)
serializers.py
from rest_framework import serializers
from .models import UserMedia
class UserMediaSerializer(serializers.ModelSerializer):
category = serializers.CharField(allow_blank=False, required=True)
class Meta:
model = UserMedia
fields = ('category',)
read_only_fields = ('category',)
def get_category(self, obj):
if obj.category:
return obj.category
return 'N/A'
def create(self, validated_data):
if validated_data['user'] is None:
raise TypeError('User media must have a user')
if validated_data['category'] is None:
raise TypeError('User media must have a category.')
if validated_data['category'] not in dict(UserMedia.CATEGORY_CHOICES):
raise TypeError('User media category is not available.')
userMedia = UserMedia(**validated_data)
userMedia.save()
return userMedia
models.py
from django.db import models
class UserMedia(models.Model):
user = models.ForeignKey('authentication.User', on_delete=models.CASCADE, related_name='media')
MUSIC = 'M'
VIDEO = 'V'
CATEGORY_CHOICES = (
(MUSIC, 'Music'),
(VIDEO, 'Video'),
)
category = models.CharField(max_length=1, choices=CATEGORY_CHOICES, blank=False)
The validation should be done in your view. The serializers should just be for serializing data. The validation should be done in your view then the serializer is called from your view. As far as this line self.model(user=user, category=category) is concerned it does not appear that you ever import user any where.
When a user inputs a url that is wrong, my Django app returns an HTML error. How can I get DRF to return a json formatted error?
Currently my urls is
from django.conf.urls import url
from snippets import views
urlpatterns = [
url(r'^snippets/$', views.snippet_list),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]
but if a user goes to 127.0.0.1:8000/snip They get the html formatted error rather than a json formatted error.
Simply way to do it, you can use raise Http404, here is your views.py
from django.http import Http404
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from yourapp.models import Snippet
from yourapp.serializer import SnippetSerializer
class SnippetDetailView(APIView):
def get_object(self, pk):
try:
return Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = SnippetSerializer(snippet)
return Response(serializer.data, status=status.HTTP_200_OK)
You also can handle it with Response(status=status.HTTP_404_NOT_FOUND), this answer is how to do with it: https://stackoverflow.com/a/24420524/6396981
But previously, inside your serializer.py
from rest_framework import serializers
from yourapp.models import Snippet
class SnippetSerializer(serializers.ModelSerializer):
user = serializers.CharField(
source='user.pk',
read_only=True
)
photo = serializers.ImageField(
max_length=None,
use_url=True
)
....
class Meta:
model = Snippet
fields = ('user', 'title', 'photo', 'description')
def create(self, validated_data):
return Snippet.objects.create(**validated_data)
To test it, an example using curl command;
$ curl -X GET http://localhost:8000/snippets/<pk>/
# example;
$ curl -X GET http://localhost:8000/snippets/99999/
Hope it can help..
Update
If you want to handle for all error 404 urls with DRF, DRF also provide about it with APIException, this answer may help you; https://stackoverflow.com/a/30628065/6396981
I'll give an example how do with it;
1. views.py
from rest_framework.exceptions import NotFound
def error404(request):
raise NotFound(detail="Error 404, page not found", code=404)
2. urls.py
from django.conf.urls import (
handler400, handler403, handler404, handler500)
from yourapp.views import error404
handler404 = error404
Makesure your DEBUG = False
from rest_framework import status
from rest_framework.response import Response
# return 404 status code
return Response({'status': 'details'}, status=status.HTTP_404_NOT_FOUND)
An easier way is to use get_object_or_404 method in django:
as described in this link:
get_object_or_404(klass, *args, kwargs)
- Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
- klass: A Model class, a Manager, or a QuerySet instance from which to get the object.
As an example, pay attention to
obj = get_object_or_404(Snippet, pk=pk)
return obj
in the following code:
from django.shortcuts import get_object_or_404
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
class SnippetDetail(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk):
obj = get_object_or_404(Snippet, pk=pk)
return obj
def get(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
...
Or simply, you can use the same structure of DRF, without losing I18N and keep the same DRF error message:
from rest_framework import viewsets, status, exceptions
from rest_framework.decorators import action
from rest_framework.response import Response
try:
codename = get_or_bad_request(self.request.query_params, 'myparam')
return Response(self.get_serializer(MyModel.objects.get(myparam=codename), many=False).data)
except MyModel.DoesNotExist as ex:
exc = exceptions.NotFound()
data = {'detail': exc.detail}
return Response(data, exc.status_code)