Why does this test keep failing? - django

I'm trying to write a simple test for some endpoints but the second one keeps failing.
Here's the test.py
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework import status
from django.urls import reverse
from .views import PostViewSet
from django.contrib.auth import get_user_model
User = get_user_model()
class PostListCreateTestCase(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.view = PostViewSet.as_view({"get": "list", "post": "create"})
self.url = reverse("post_list")
self.user = User.objects.create(
email="testuser#gmail.com", name="testuser", password="pass"
)
def test_list_posts(self):
request = self.factory.get(self.url)
response = self.view(request)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_create_post(self):
sample_post = {
"title": "sample title",
"body": "sample body",
}
request = self.factory.post(self.url, sample_post)
request.user = self.user
response = self.view(request)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
And here's the view:
from rest_framework import viewsets, status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from .serializers import PostSerializer, LikeSerializer
from .models import Post, Like
class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
queryset = Post.objects.all()
def get_queryset(self):
posts = Post.objects.all()
return posts
def get_object(self):
post = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, post)
return post
def create(self, request, *args, **kwargs):
try:
post = Post.objects.create(
title=request.data.get("title"),
body=request.data.get("body"),
author=request.user,
)
post = PostSerializer(post)
return Response(post.data, status=status.HTTP_201_CREATED)
except Exception as ex:
return Response(str(ex), status=status.HTTP_400_BAD_REQUEST)
def list(self, request, *args, **kwargs):
posts = self.get_queryset()
serializer = self.get_serializer(posts, many=True)
return Response(
data=dict(posts=serializer.data, total=len(serializer.data)),
status=status.HTTP_200_OK,
)
That's what I get:
Found 2 test(s). Creating test database for alias 'default'... System
check identified no issues (0 silenced). F.
====================================================================== FAIL: test_create_post (posts.tests.PostListCreateTestCase)
---------------------------------------------------------------------- Traceback (most recent call last): File
"/home/amr/Snakat/social_network/posts/tests.py", line 31, in
test_create_post
self.assertEqual(response.status_code, status.HTTP_201_CREATED) AssertionError: 400 != 201
---------------------------------------------------------------------- Ran 2 tests in 0.023s
FAILED (failures=1) Destroying test database for alias 'default'...

Related

DjangoModelPermissions not working with DRF

I am trying to use Django Rest Framework and face a problem. The problem is when i try to use DjangoModelPermissions it doesn't follow the permission from Django admin panel.
What I excepted, is that when I set permission Projects|projects|can view projects then user can see the output.
Here are my codes:
Views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAdminUser, IsAuthenticated, DjangoModelPermissions
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from .models import Projects
from .serializers import ProjectSerializer
class ProjectsViewSet(viewsets.ViewSet):
permission_classes_by_action = {'list': [DjangoModelPermissions]}
queryset = Projects.objects.none()
serializer_class = ProjectSerializer
def list(self, request):
queryset = Projects.objects.all()
serializer = ProjectSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Projects.objects.all()
project = get_object_or_404(queryset, pk=pk)
serializer = ProjectSerializer(project)
return Response(serializer.data)
def get_permissions(self):
try:
return [permission() for permission in self.permission_classes_by_action[self]]
except KeyError:
return [permission() for permission in self.permission_classes]
serializers.py
from rest_framework import serializers
from .models import Projects
class ProjectSerializer(serializers.ModelSerializer):
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
class Meta:
model = Projects
fields = ('id','name')
Django admin site permission for the user: []
Output
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"id": 1,
"name": "proj 1"
},
{
"id": 2,
"name": "proj 222"
}
]
I don't know if it would help but, I am using custom User AUTH_USER_MODEL="users.Users"
Thanks in advance

Django - BaseSerializer.is_valid() takes 1 positional argument but 2 were given

This project was working before, but then Heroku took away free tier so I have been trying to deploy somewhere else, but now all of a sudden I cannot even create a user locally even though I could before... Now when I create a user I get the error mentioned in the title.
serializers folder
common.py file
from xml.dom import ValidationErr
from rest_framework import serializers
from django.contrib.auth import get_user_model, password_validation
from django.contrib.auth.hashers import make_password
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
confirm_password = serializers.CharField(write_only=True)
def validate(self, data):
password = data.pop('password')
confirm_password = data.pop('confirm_password')
if password != confirm_password:
raise ValidationErr({ 'confirm_password': 'Does not match the password'})
password_validation.validate_password(password)
data['password'] = make_password(password)
return data
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'confirm_password')
views.py file
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import PermissionDenied
from django.contrib.auth import get_user_model
import jwt
User = get_user_model()
from datetime import datetime, timedelta
from jwt_auth.serializers.common import UserSerializer
from django.conf import settings
class RegisterView(APIView):
def post (self, request):
create_user = UserSerializer(data=request.data)
try:
create_user.is_valid(True)
create_user.save()
return Response(create_user.data, status=status.HTTP_201_CREATED)
except Exception as e:
print(str(e))
return Response(e.__dict__ if e.__dict__ else str(e), status=status.HTTP_422_UNPROCESSABLE_ENTITY)
class LoginView(APIView):
def post(self, request):
password = request.data.get('password')
username = request.data.get('username')
try:
user_login = User.objects.get(username=username)
except User.DoesNotExist:
raise PermissionDenied('Credentials are incorrect!')
if not user_login.check_password(password):
raise PermissionDenied('Credentials are incorrect!')
dt = datetime.now() + timedelta(days=7)
token = jwt.encode(
{
'sub': user_login.id,
'exp': int(dt.strftime('%s'))
},
settings.SECRET_KEY,
'HS256'
)
print('TOKEN ----->', token)
return Response({ 'token': token, 'message': f'Welcome back {user_login.username}' })
rest-framework branch "3.9.x" (github)
def is_valid(self, raise_exception=False):
...
rest-framework branch "master" (github)
def is_valid(self, *, raise_exception=False):
...
so "master" now: is_valid() only accepts keyword argument "raise_exception=True":
class RegisterView(APIView):
def post (self, request):
create_user = UserSerializer(data=request.data)
try:
create_user.is_valid(raise_exception=True)
....
Change it into something like this:
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
return Response(user.data, status=status.HTTP_201_CREATED)
the rest of your code...

Django object on creation isn't stored in the database and the ID is returned as null

I'm creating a basic notes application where user can perform CRUD operation.
Following are my models, views and URLs.
from django.db import models
from accounts.models import User
from django.utils import timezone
class Notes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
if not self.id:
self.created_on = timezone.now()
self.last_updated = timezone.now()
def __str__(self):
return self.title
Views.py
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets, status
from rest_framework.response import Response
from . import serializers, models
class NotesViewSet(viewsets.ModelViewSet):
queryset = models.Notes.objects.all()
serializer_class = serializers.NotesSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def list(self, request):
notes = models.Notes.objects.all().filter(user=request.user)
serializer = serializers.NotesSerializer(notes, many=True)
return Response(serializer.data)
def create(self, request):
serializer = serializers.NotesSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def retrieve(self, request, pk=None):
note = models.Notes.objects.filter(id=pk)
serializer = serializers.NotesSerializer(instance=note)
return Response(serializer.data)
def update(self, request, pk=None):
note = models.Notes.objects.get(id=pk)
serializer = serializers.NotesSerializer(
instance=note, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
def destroy(self, request, pk=None):
note = models.Notes.objects.get(id=pk)
note.delete()
return Response({"message": "Note deleted"},
status=status.HTTP_202_ACCEPTED)
urls.py
from django.urls import path
from .views import NotesViewSet
app_name = 'notes'
urlpatterns = [
path('get', NotesViewSet.as_view({
'get': 'list',
}), name='get'),
path('create', NotesViewSet.as_view({
'post': 'create',
}), name='create'),
path('get/<str:pk>', NotesViewSet.as_view({
'get': 'retrieve',
}), name='retrieve'),
path('update/<str:pk>', NotesViewSet.as_view({
'put': 'update',
}), name='update'),
path('delete/<str:pk>', NotesViewSet.as_view({
'delete': 'destroy',
}), name='delete'),
]
My question is, once I send a post request to create a new note something like this coming back as a response
{
"id": null,
"title": "title_1",
"body": "body_1",
"created_on": "2021-06-02T21:10:42.019236+05:30",
"last_updated": "2021-06-02T21:10:42.019257+05:30",
"user": 1
}
and the data isn't stored in the database as well. Please help
I believe the issue is in how you've overridden your save method- you still need to call the parent's save on it to get your expected behavior.
def save(self, *args, **kwargs):
if not self.id:
self.created_on = timezone.now()
self.last_updated = timezone.now()
super().save(*args, **kwargs)
Your code has some odd tabulation under your Notes class- I'm assuming this is just an issue in the code within the question.
super()
in save method is missing. You need to call super().save(*args, **kwargs) to make it work.

How can I fix django rest framework metaclass conflict

I am a beginner learning django rest framework and I just encounter this error and I can't seem to find a way around it. Here is the permissions.py sample code
from rest_framework import permissions
class UpdateOwnProfile(permissions, BaseException):
"""Allow user to edit their own profile"""
def has_object_permission(self, request, view, obj):
"""Check if user is trying to update their own profile"""
if request.method in permissions.SAFE_METHODS:
return True
return obj.id == request.user.id
Here is also a sample of the views.py sample codes
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework import viewsets
from rest_framework.authentication import TokenAuthentication
from profiles_api import serializers
from profiles_api import models from profiles_api import permissions
class HelloApiView(APIView): """Test Api view""" serializer_class = serializers.HelloSerializer
def get(self, request, format=None):
"""Returns a list of Api features"""
an_apiview = [
'Uses HTTP methods as function (get, post, patch, put, delete)',
'Is similar to a traditional Django view',
'Gives you the most control over your application logic',
'Is mapped manually to URLs',
]
return Response({'message': 'Hello', 'an_apiview': an_apiview})
def post(self, request):
"""Create a hello message with our name"""
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
name = serializer.validated_data.get('name')
message = f'Hello {name}'
return Response({'message': message})
else:
return Response(
serializer.errors,
status = status.HTTP_400_BAD_REQUEST
)
def put(self, request, pk=None):
"""Handling updates of objects"""
return Response({'method': 'PUT'})
def patch(self, request, pk=None):
"""Handle a partial update of an object"""
return Response({'method': 'PATCH'})
def delete(self, request, pk=None):
"""Delete an object"""
return Response({'method': 'DELETE'})
class HelloViewset(viewsets.ViewSet): """Test API Viewset""" serializer_class = serializers.HelloSerializer
def list(self, request):
"""Return a hello message"""
a_viewset = [
'Uses actions (list, create, retrieve, update, partial update'
'Automatically maps to URLs using router'
'provides more functionality with less code'
]
return Response({'message': 'Hello', 'a_viewset': a_viewset})
def create(self, request):
"""Create a new hello message"""
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
name = serializer.validated_data.get('name')
message = f'Hello {name}!'
return Response({'message': message})
else:
return Response(
serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
def retrieve(self, request, pk=None):
"""Handle getting an object by its ID"""
return Response({'http_method': 'GET'})
def update(self, request, pk=None):
"""Handle updating an object"""
return Response({'http_method': 'PUT'})
def partial_update(self, request, pk=None):
"""Handle updating of an object"""
return Response({'http_method': 'PATCH'})
def destroy(self, request, pk=None):
"""Handle removing an object"""
return Response({'http_method': 'DELETE'})
class UserProfileViewSet(viewsets.ModelViewSet): """Handle creating and updating profiles""" serializer_class = serializers.UserProfileSerializer queryset = models.UserProfile.objects.all() authentication_classes = (TokenAuthentication,) permission_classes = (permissions.UpdateOwnProfile,)
And while running the development server I get this error:
class UpdateOwnProfile(permissions, BaseException): TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
permissions (rest_framework.permissions) is of type module (whose type is type FWIW), but the type of BaseException is type (like all regular classes). So you have a metaclass conflict as expected.
Presumably, you meant to use permissions.BasePermission class from the module:
class UpdateOwnProfile(permissions.BasePermission, BaseException):
...
...
You can also import and refer the class directly:
from rest_framework.permissions import BasePermission
class UpdateOwnProfile(BasePermission, BaseException):
...
...

"detail": "CSRF Failed: CSRF token missing or incorrect."

I'm making RESTful API using Tastypie, and when I try to POST/PUT/DELETE a request it says:
"detail": "CSRF Failed: CSRF token missing or incorrect.".
It works fine with GET. I've read various threads on SO, saying:
to delete the cookies
or use #csrf_exempt
or use #method_decorator(csrf_exempt)
but neither of it worked.
How can I over-pass this error?
views.py
class SnippetList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
request._dont_enforce_csrf_checks = True
print request.DATA
return self.create(request, *args, **kwargs)
serializer.py
from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
urls.py
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = patterns('',
url(r'^snippets/$', views.SnippetList.as_view()),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
)
urlpatterns = format_suffix_patterns(urlpatterns)
Change rest_framework default permissions to AllowAny in settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
...
}