I am trying to run an application that uses django rest framework.However am getting the import error "cannot import name DurationField".How do i resolve this error ?
Error message
enter image description here
Views.py
from django.shortcuts import render
from django.contrib.auth.models import User
from django.http import Http404
from restapp.serializers import UserSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class UserList(APIView):
#List all user,create new one
def get(self,request,format=None):
users = User.objects.all()
serializer = UserSerializer(users,many=True)
return Response(serializer.data)
def post(self,request,format=None):
serializer= UserSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,pk, format=None):
user = self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class UserDetail(APIView):
#Retrive update,or delete a user instance
def get_object(self,pk):
try:
return User.objects.get(pk=pk)
except user.DoesNotExist:
raise 404
def get(self,request,pk,format=None):
user = self.get_object(pk)
user = UserSerializer(user)
return Response(user.data)
def put(self,request,pk,format=None):
user = self.get_object(pk)
serializer=UserSerializer(user,data = request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,pk,format=None):
user = self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','username','firstname','last_name','email')
It points to this file serializers.py,line 18 as source of error.
enter image description here
From the screenshot, I can see you're using Django 1.7.
The DurationField that is being imported by DRF was introduced in Django 1.8.
So you have to upgrade your Django to get this version of DRF to work.
Related
I'm very new to Django and preparing for the DRF Session.
I have to write code in Serializers.py and views.py for Logout function but I don't know what to do and where to start.
Can you please help? Here's some code for register and login
Serialzers.py
from rest_framework import serializers
from .models import *
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'password']
def create(self, validated_data):
user = User.objects.create(
email=validated_data['email'], username=validated_data['username'],)
user.set_password(validated_data['password'])
user.save()
return user
class UserLoginSerializer(serializers.Serializer):
email = serializers.CharField(max_length=64)
password = serializers.CharField(max_length=128, write_only=True)
def validate(self, data):
email = data.get("email", None)
password = data.get("password", None)
if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
if not user.check_password(password):
raise serializers.ValidationError()
else:
return user
else:
raise serializers.ValidationError()
class UserLogoutSerializer(serializers.Serializer):
# I have to do this part
views.py
from django.shortcuts import get_object_or_404, render
from .serializers import *
from .models import *
from rest_framework import views
from rest_framework.response import Response
class SignUpView(views.APIView):
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': 'Success', 'data': serializer.data})
return Response({'message': 'Fail', 'error': serializer.errors})
class LoginView(views.APIView):
def post(self, request):
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
return Response({'message': "Success", 'data': serializer.data})
return Response({'message': "Fail", 'data': serializer.errors})
class LogoutView(views.APIView):
You do not necessarily have to use a serializer. Logout can be as simple as calling an endpoint once (logout just disables any active authorization token). Try this:
from django.contrib.auth import logout
class LogoutView(views.APIView):
def post(self, request):
logout(request)
return Response({'message': "Logout successful"})
It depends on how you are authenticating your user. From you code, I do not see how you actually authenticate your user (you only seem to check if the user exists, you do not give them an authorization token anywhere). Basically I am not sure how one would log out in your current architecture as there is no user logged in ever to log them out.
You might want to consider token authentication.
I'm new to django rest framework. I'm implementing a simple login, signup and forgot password functionality using reactJs and django. All the functionalities are working fine but the problem I'm facing is that, on signup, the passwords in the database encrypted and then saved in the database but on updating password, the new password saved exactly same as user typed it. I want it also be encrypted in the database just like it encrypted in signup.
My serializer.py file
from dataclasses import fields
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields='__all__'
# fields = ('username','first_name', 'last_name', 'email')
class UserSerializerWithToken(serializers.ModelSerializer):
token = serializers.SerializerMethodField()
password = serializers.CharField(write_only=True)
def get_token(self, obj):
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(obj)
token = jwt_encode_handler(payload)
return token
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class Meta:
model = User
fields = ('token','first_name', 'last_name','email', 'username', 'password')
My views.py file
from asyncio.windows_events import NULL
from django.http import Http404, HttpResponseRedirect
from django.contrib.auth.models import User
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserSerializer
from .serializers import UserSerializerWithToken
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
#api_view(['GET'])
def current_user(request):
"""
Determine the current user by their token, and return their data
"""
serializer = UserSerializer(request.user)
return Response(serializer.data)
#api_view(['GET'])
def get_user(request):
"""
Filter the user wrt username and return the user data and token
"""
user=User.objects.filter(email=request.query_params['email'])
serializer = UserSerializer(instance=user, many=True)
if user.exists():
return Response(serializer.data)
else:
return Response(serializer.errors)
# ########################################################
# This is my update user api to update password
# it updates the password but not encrypting the password
# like signup encrypts in database
# ########################################################
#api_view(['PUT'])
def update_user(request,id):
user=User.objects.get(pk=id)
# userdata={'id':user.id,'username':user.username,'first_name':user.first_name,'last_name':user.last_name,'password':user.password}
serializer=UserSerializer(instance=user, data=request.data[0])
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class UserList(APIView):
"""
Create a new user. It's called 'UserList' because normally we'd have a get
method here too, for retrieving a list of all User objects.
"""
# permission_classes = (permissions.AllowAny,)
def post(self, request, format=None):
serializer = UserSerializerWithToken(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# ############################################################################
# I tried the following way as well but it doesn't even update the password
# ############################################################################
#
# def put(self,request,id,format=None):
# user=User.objects.get(pk=id)
# serializer=UserSerializerWithToken(instance=user, data=request.data)
# if serializer.is_valid():
# serializer.save()
# return Response(serializer.data)
# else:
# return Response(serializer.errors)
This is the url I'm using for api
path('users/<int:id>/',UserList.as_view()),
And this is how I called this api from reactjs
function handleSubmit(e) {
let user=JSON.parse(localStorage.getItem('matched_user_token'))[0]
user.password=new_password
e.preventDefault()
if (ValidatePassword()) {
fetch('http://localhost:8000/core/users/'+user.id+'/', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
.then(res => res.json())
.then(json => {
console.log("password changed successfully!"+json)
localStorage.setItem('changed',true)
navigate('/login')
}).catch(errors=>console.log(errors))
}
}
You need to override serializer's update method like this:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields='__all__'
def update(self, instance, validated_data):
if 'password' in validated_data:
password = validated_data.pop('password', None)
instance.set_password(password)
return super().update(instance, validated_data)
I am new to Django, I was wondering How to code PUT request and Delete method in my Django REST API Project.
I have tried to follow with many tutorials, but none working with my kind of code.
The code I tried looks like this
def put(self, request, pk):
snippet = self.get_object(pk)
serializer = UserSerializers(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
snippet = self.get_object(pk)
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
But getting message method not allowed
The following is my Models.py
from django.db import models
class Users(models.Model):
user_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
profile_name = models.CharField(max_length=30)
profile_picture = models.CharField(max_length=1000)
phone = models.CharField(max_length=15)
email = models.EmailField()
password = models.CharField(max_length=25, default='')
def __str__(self):
return self.name
The following is my serializers.py
from rest_framework import serializers
from .models import Users
from .models import UserPost
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = Users
fields = '__all__'
class UserDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = '__all__'
class UserPostSerializers(serializers.ModelSerializer):
class Meta:
model = UserPost
fields = '__all__'
The following code contains my Views.py
from django.http import Http404
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from .models import Users
from .models import UserPost
from .serializers import UserSerializers, UserPostSerializers
class UsersList(APIView):
def get(self, request):
User_details = Users.objects.all()
serializer = UserSerializers(User_details, many=True)
return Response(serializer.data)
def post(self, request):
serializer = UserSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserDetail(APIView):
def get_object(self, pk):
try:
return Users.objects.get(pk=pk)
except Users.DoesNotExist:
raise Http404
def get(self, request, pk):
snippet = self.get_object(pk)
serializer = UserSerializers(snippet)
return Response(serializer.data)
class UserViewSet(viewsets.ModelViewSet):
queryset = Users.objects.all()
serializer_class = UserSerializer
#action(methods=['put'], detail=False)
def filter_by_something(self, request):
something = request.data.get('that_something')
queryset = Users.objects.filter(something__exact=something)
return Response(self.get_serializer(queryset, many=True).data)
The following code contains urls.py
from sys import path
from django.urls import include
from rest_framework.urlpatterns import format_suffix_patterns
from app import views
from django.conf.urls import url
from django.contrib import admin
from rest_framework import routers
router = routers.DefaultRouter()
router.register('user_details', UserDetailViewSet)
urlpatterns = [path('api/', include(router.urls)), ...]
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^User_details/', views.UsersList.as_view()),
url(r'^User_details/(?P<pk>[0-9]+)/', views.UserDetail.as_view()),
url(r'^userpost_details/', views.UsersPostList.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
Define put & delete methods in UsersDetail class.
class UsersDetail(APIView):
def put(self, request, pk):
// code
def delete(self, request, pk):
//code
If the above does not work also add http_method_names
class UsersDetail(APIView):
http_method_names = ['GET', 'PUT', 'DELETE']
class APIView inherits from class View defined in the base file of Django. dispatch method will check http_method_names for valid method. PUT and DELETE is listed as valid methods along with others.
Reference: django/views/generic/base.py
class View(object):
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning('Method Not Allowed (%s): %s', request.method, request.path,
extra={
'status_code': 405,
'request': request
}
)
return http.HttpResponseNotAllowed(self._allowed_methods())
In urls.py you should declare a router object that maps your ViewSets to DRF:
from rest_framework import routers
router = routers.DefaultRouter()
router.register('user_details', UserDetailViewSet)
urlpatterns = [path('api/', include(router.urls)), ...]
UserDetailViewSet must be declared in api\views.py (api is the directory for DRF application)
from rest_framework.decorators import action
from rest_framework import viewsets
from rest_framework.response import Response
class UserDetailViewSet(viewsets.ModelViewSet):
queryset = UserDetail.objects.all()
serializer_class = UserDetailSerializer
#action(methods=['put'], detail=False)
def filter_by_something(self, request):
something = request.data.get('that_something')
queryset = UserDetail.objects.filter(something__exact=something)
return Response(self.get_serializer(queryset, many=True).data)
Then you will make PUT requests on http:\\your_website\api\user_details\filter_by_something
Try something like this. It should work!
I was following the Django restful framework tutorial and I came across a error at the "Authenticating with the API" step. I've retraced myself however can't seem to see where I went wrong. Basically when I go to post to my API i get an error see below. Ideally I would also like to setup permissions which state "access denied" unless object owner - any advice on this would be greatly appreciated.
http -a jimmynos:password POST http://127.0.0.1:8000/snippets/ code="print 789"
Some of the error:
IntegrityError at /snippets/
NOT NULL constraint failed: snippets_snippet.owner_id
Request Method: POST
Request URL: http://127.0.0.1:8000/snippets/
Django Version: 1.9.9
Python Executable: /Users/james/Documents/django/tutorialSerialization/env/bin/python
Python Version: 2.7.10
Python Path: ['/Users/james/Documents/django/tutorialSerialization/tutorial', '/Users/james/Documents/django/tutorialSerialization/env/lib/python27.zip', '/User
views.py
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth.models import User
from snippets.serializers import UserSerializer
from rest_framework import generics
from rest_framework import permissions
from snippets.permissions import IsOwnerOrReadOnly
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly,)
def get(self, request, format=None):
#snippets = Snippet.objects.all()
snippets = Snippet.objects.filter(owner=self.request.user)
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly,)
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)
def put(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
snippet = self.get_object(pk)
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
serializers.py
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
from django.contrib.auth.models import User
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
#owner = serializers.ReadOnlyField(source='owner.username')
fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'snippets')
permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
The error must have something to do with
owner = serializers.ReadOnlyField(source='owner.username')
or
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
models.py
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
owner = models.ForeignKey('auth.User', related_name='snippets')
highlighted = models.TextField()
class Meta:
ordering = ('created',)
Enviroment:
Python 2.7.10 on MAC
Django==1.9.9
djangorestframework==3.4.6
Pygments==2.1.3
Django Restful Framework API
The error should be owner = serializers.ReadOnlyField(source='owner.username')
Your serializer need owner to create Snippet instance.
If you let owner to be readonly, then you will lack the owner field, therefore it failed to create snippet instance.
Make sure you also add 'owner', to the list of fields in the inner Meta class.
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
fields = ('id', 'title', 'code', 'linenos', 'language', 'style','owner')
As per the DRF documentation, the serializer_class attribute should be set when using GenericAPIView. But why does the serializer_class attribute even works with APIView?
Here is my API code:
class UserView(APIView):
serializer_class = SignupSerializer
#transaction.atomic
def post(self, request):
email = get_data_param(request, 'email', None)
password = get_data_param(request, 'password', None)
params = request.POST.copy()
params["username"] = email
serializer = UserSerializer(data=params)
if serializer.is_valid(raise_exception=True):
user = serializer.save()
user.set_password(password)
user.save()
params["user"] = user.id
serializer = CustomProfileSerializer(data=params)
if serializer.is_valid(raise_exception=True):
profile = serializer.save()
return Response(response_json(True, profile.to_dict(), None))
class SignupSerializer(serializers.Serializer):
email = serializers.EmailField(max_length=100)
password = serializers.CharField(max_length=50)
When I browse this API in the browser it does show the email and password fields as input but if I don't set this serializer_class attribute, no input fields are shown.
Ideally, this serializer_class attribute should not work with APIView. I have searched a lot but there is nothing available related to this.
Can anyone please provide an explanation for this behavior? Thanks.
I think this can help you.
create serializer.py and write:
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'password')
and views.py:
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserSerializer
from .models import User
class AddUserAPIView(APIView):
def post(self, request):
user_serializer = UserSerializer(data=request.data)
if user_serializer.is_valid():
user = user_serializer.save()
user.set_password(user_serializer.data["password"])
return Response({'message': 'user added successfully!'})
return Response({'message': user_serializer.errors})
You are absolutely right!!:
APIView doesn't utilize a serializer_class (by default) because it is not meant to handle any request processing logic!
What happens though is that the BrowsableAPIRenderer that is used to render the API in the browser checks for a serializer_class attribute and set's it as the View serializer if it exists. We can see this in the BrowsableAPIRenderer code:
The _get_serializer class of the renderer:
def _get_serializer(self, serializer_class, view_instance, request, *args, **kwargs):
kwargs['context'] = {
'request': request,
'format': self.format,
'view': view_instance
}
return serializer_class(*args, **kwargs)
And the way it is used to set the renderer serializer if it exists, inside the get_rendered_html_form:
Line 483: has_serializer_class = getattr(view, 'serializer_class', None)
Lines 497 to 509:
if has_serializer:
if method in ('PUT', 'PATCH'):
serializer = view.get_serializer(instance=instance, **kwargs)
else:
serializer = view.get_serializer(**kwargs)
else:
# at this point we must have a serializer_class
if method in ('PUT', 'PATCH'):
serializer = self._get_serializer(view.serializer_class, view,
request, instance=instance, **kwargs)
else:
serializer = self._get_serializer(view.serializer_class, view,
request, **kwargs)
In essence, you accidentally override the BrowserAPIRenderer's default behavior regarding the APIView by providing the serializer_class attribute. For what is worth, my opinion on the matter is that this should not be possible!
I use the django rest framework default get_schema_view() to provide auto-generated openapi schema from which I auto generate a javascript client for.
This works for ViewSets, but the payload wasn't being provided for views defined by APIView.
Where I have defined serializers, I found that adding get_serializer() method to my APIView classes allowed the schema to be generated with the serializer defined payload.
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserSerializer
from .models import User
class AddUserAPIView(APIView):
def get_serializer(self, *args, **kwargs):
return UserSerializer(*args, **kwargs)
def post(self, request):
user_serializer = UserSerializer(data=request.data)
if user_serializer.is_valid():
user = user_serializer.save()
user.set_password(user_serializer.data["password"])
return Response({'message': 'user added successfully!'})
return Response({'message': user_serializer.errors})