Token based authentication with Django REST Framework - python

I'm practicing through the django rest_framework documentation and struck at authentication, especially token based authentication. I'm able to create token for user which already created. Now the thing is how to give permissions to users add, delete, update the information by providing the token. I have done some stuff, below
models.py
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', on_delete=models.CASCADE)
highlighted = models.TextField(default = '')
class Meta:
ordering = ('created',)
views.py
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer,UserSerializer
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 rest_framework import generics
from rest_framework import permissions
from snippets.permissions import IsOwnerOrReadOnly
class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
snippets = Snippet.objects.all()
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)
permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly,)
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)
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
serializers.py
from rest_framework import serializers
from snippets.models import Snippet
from django.contrib.auth.models import User
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style','owner')
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
#owner = serializers.ReadOnlyField(source='owner.username')
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
ulrs.py
from django.conf.urls import url,include
from snippets import views
import rest_framework
#rfrom rest_framework.authtoken import views
urlpatterns = [
url(r'^snippets/$', views.SnippetList.as_view()),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
url(r'^api-token-auth/', rest_framework.authtoken.views.obtain_auth_token),
url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
Error:
>>> from snippets.models import Snippet
>>> from snippets.serializers import SnippetSerializer
>>> from rest_framework.renderers import JSONRenderer
>>> from rest_framework.parsers import JSONParser
>>> snippet = Snippet(code='foo = "bar"\n')
>>> snippet.save()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/phygital/kiran/snippets/models.py", line 56, in save
super(Snippet, self).save(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 736, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 820, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 859, in _do_insert
using=using, raw=raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 1039, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 1060, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py", line 323, in execute
return Database.Cursor.execute(self, query, params)
IntegrityError: NOT NULL constraint failed: snippets_snippet.owner_id

Token Authentication using Django rest framework.
views.py
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class SampleView(APIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
create Token for using in normal view or signal(post save method)
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=your instance)
Pass the parameter as the Token in the Header of the request, as said in Django Rest Framework documentation:
For clients to authenticate, the token key should be included in the
Authorization HTTP header. The key should be prefixed by the string
literal "Token", with whitespace separating the two strings. For
example:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Related

How to override admin save_model method

I use slugify to create slugs for my blog's posts urls. In order to accept in the slug also non english characters (greek), I overrode Post model's save() method, with one that includes a parameter allow_unicode=True. However that couldn't work in admin area. Whenever I tried to set a greek characters slug in admin area either by setting a new post with greek title, or by editing the english slug of an existing post, admin form wouldn't allow me to save. For that, as I found in other threads, I should override the save_model() method in admin.py file. So I did, but I get an error. Now the error I get points out that admin area requested the post whose slug is going to change with the old url (an id based one), instead of the slug-url I set in the urls.py.
The error I get is either an AttribureError at /admin/blog/post/1 (when I'm editing the slug of an existing post), or an AttribureError at /admin/blog/post/add (when I'm adding a new post). And the exception value in both cases is 'WSGIRequest' object has no attribute 'save'
How should I set admin-side save methods to request the urls using slug urls?
Thank you in advance!
models.py:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from ckeditor.fields import RichTextField
from django.utils.text import slugify
from taggit.managers import TaggableManager
class Post(models.Model):
title = models.CharField(max_length=100)
content = RichTextField(blank=True, null=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
is_published = models.BooleanField(default=True)
slug = models.SlugField(unique=True, max_length=100)
tags = TaggableManager(blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title, allow_unicode=True)
super(Post, self).save(*args, **kwargs)
admin.py:
from django.contrib import admin
from .models import Post
from django.utils.text import slugify
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
list_display = ('title', 'slug', 'is_published', 'author', 'date_posted')
list_editable = ('is_published',)
def save_model(self, request, obj, form, change):
if not obj.slug:
obj.slug = slugify(obj.title, allow_unicode=True)
super(PostAdmin, self).save_model(self, request, obj, form)
admin.site.register(Post, PostAdmin)
urls.py:
from django.urls import path, register_converter, re_path
from .views import (
PostListView,
UserPostListView,
PostDetailView,
PostCreateView,
PostUpdateView,
PostDeleteView,
TagIndexView
)
from django.urls.converters import SlugConverter
class CustomSlugConverter(SlugConverter):
regex = '[-\w]+'
register_converter(CustomSlugConverter, 'custom_slug')
urlpatterns = [
path('front_page', PostListView.as_view(), name='blog-home'),
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
re_path(r'post/(?P<slug>[\w-]+)/$', PostDetailView.as_view(), name='post-detail'),
path('post/new/', PostCreateView.as_view(), name='post-create'),
re_path(r'post/(?P<slug>[\w-]+)/update$', PostUpdateView.as_view(), name='post-update'),
re_path(r'post/(?P<slug>[\w-]+)/delete$', PostDeleteView.as_view(), name='post-delete'),
path('tag/<slug>', TagIndexView.as_view(), name='tag-posts'),
]
EDIT: Here is the error traceback:
Traceback (most recent call last):
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 614, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 233, in inner
return view(request, *args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1656, in change_view
return self.changeform_view(request, object_id, form_url, extra_context)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1534, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1580, in _changeform_view
self.save_model(request, new_object, form, not add)
File "/home/george/PythProj/myWebsite/blog/admin.py", line 15, in save_model
super(PostAdmin, self).save_model(self, request, obj, form)
File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1093, in save_model
obj.save()
Exception Type: AttributeError at /admin/blog/post/1/change/
Exception Value: 'WSGIRequest' object has no attribute 'save'
EDIT2: The solution to avoid the error was of course to write my super() method in a correct way. However that didn't give to my code the functionality I wanted. So what seems to be the solution to my problem, is to declare the slug in my model as a CharField, instead of SlugField. In that case I can even remove my save_model() method that was the reason for the post. Now I'm checking if is going to be any side effect of removing the SlugField. If not I should find the thread I saw that solution to give the credit, if there are side effects I should restore SlugField and find a way to override its validate_slug class. That's all, thank you guys for your response!
EDIT3: Hadn't notice that allow_unicode=True could be argument not only for slugify(), but also for models.SlugField()... So that was for me the final solution...
when you call super() method, you should not pass self there as a parameter. So instead of your current code:
def save_model(self, request, obj, form, change):
super(PostAdmin, self).save_model(self, request, obj, form)
you should call the super() without self as a parameter, and add the missing change on the end:
def save_model(self, request, obj, form, change):
super(PostAdmin, self).save_model(request, obj, form, change)

(Django) 'CommentView' object has no attribute 'body'

I have been trying to emulate comment functionality with a decorator.
import json
import jwt
from django.views import View
from django.http import JsonResponse
from functools import wraps
from django.db.models import Q
from .models import Comment
from account.models import Account
class CommentView(View):
def login_required(func):
#wraps(func)
def wrapper(request, *args, **kwargs):
# import pdb; pdb.set_trace()
given_token = json.loads(request.body)['access_token']
decoded_token = jwt.decode(given_token,None,None)
try:
if Account.objects.filter(username=decoded_token).exists():
return func(request, *args, **kwargs)
return JsonResponse({"message": "username does not exist"})
except KeyError:
return JsonResponse({"message": "INVALID_KEYS"}, status=403)
return wrapper
#login_required
def post(self, request):
print("request ", json.loads(request.body))
data = json.loads(request.body)
Comment.objects.create(
username = jwt.decode(json.loads(request.body)['access_token']),
content = data['content'],
)
return JsonResponse({"message":"Comment Created!"}, status=200)
def get(self, request):
return JsonResponse({'comment':list(Comment.objects.values())}, status=200)
And I used the program called Httpie to give JSON POST request like so:
http -v http://127.0.0.1:8000/comment access_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImJlY2sifQ.2unop67pLHOshcGs385GwOvaZZW_J--TRNXyHI3gKNU" content="hello"
There is no problem with the token since this is the exact copy of the token give during the SignInView(which is in another app).
Below is the models.py file in the 'comment' app.
from django.db import models
from account.models import Account
class Comment(models.Model):
username = models.ForeignKey(Account, on_delete=models.CASCADE)
content = models.TextField()
created_time= models.DateTimeField(auto_now_add = True)
updated_time= models.DateTimeField(auto_now = True)
class Meta:
db_table = 'comments'
def __str__(self):
return self.username + ": " + self.content
However, when I send the POST request with the Httpie like above, I get this error:
Internal Server Error: /comment
Traceback (most recent call last):
File "/Users/woohyunan/miniconda3/auth/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/woohyunan/miniconda3/auth/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/woohyunan/miniconda3/auth/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/woohyunan/miniconda3/auth/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/woohyunan/miniconda3/auth/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/Users/woohyunan/projects/Wecode/westagram/KillaGramz-backend/comment/views.py", line 19, in wrapper
given_token = json.loads(request.body)['access_token']
AttributeError: 'CommentView' object has no attribute 'body'
[20/May/2020 17:35:40] "POST /comment HTTP/1.1" 500 73224
I have been wondering what would cause the error. I wonder if there is no way to put the json request body into the decorator which would allow me to decode the token(the decoded version will be the username) so that I can see if it matches with the username in the database.
Thank you so much!!
I solved the problem!
def wrapper(request, *args, **kwargs):
needs to be
def wrapper(self, request, *args, **kwargs):

Django REST Framework: 'BasePermissionMetaclass' object is not iterable

Python/Django n00b moving over from javascript.
Trying to add an API endpoint using Django REST Framework which I'm hoping will ultimately be able to update a User with the body of a PATCH request, but for now I just want it to not throw a 500 error.
I've added this to urlpatterns:
url(r'update/$', views.UpdateView.as_view(), name="update_user"),
And that should bring in this view:
from django.contrib.auth.models import User
from rest_framework.generics import UpdateAPIView
from .serializers import UserSerializer
class UpdateView(UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
The UserSerializer looks like this:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'pk', 'status')
Seem to be getting this every time I visit the route:
TypeError at /api/update/
'BasePermissionMetaclass' object is not iterable
I have no idea what I'm doing - anyone seen this before?
UPDATE: Full Traceback:
Internal Server Error: /api/update/
Traceback (most recent call last):
File "path/to/myapp/env/lib/python2.7/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "path/to/myapp/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "path/to/myapp/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "path/to/myapp/env/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "path/to/myapp/env/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 495, in dispatch
response = self.handle_exception(exc)
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 455, in handle_exception
self.raise_uncaught_exception(exc)
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 483, in dispatch
self.initial(request, *args, **kwargs)
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 401, in initial
self.check_permissions(request)
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 333, in check_permissions
for permission in self.get_permissions():
File "path/to/myapp/env/lib/python2.7/site-packages/rest_framework/views.py", line 280, in get_permissions
return [permission() for permission in self.permission_classes]
TypeError: 'BasePermissionMetaclass' object is not iterable
You have mistyped the comma in DEFAULT_PERMISSION_CLASSES value, due to which Django takes it as a string, instead of a tuple.
Solution:
REST_FRAMEWORK = {
...
'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAdminUser', ),
...
}
I had the same problem, but looked for wrong place. I made mixin class with permissions and there was code
permission_classes = (
permissions.IsAuthenticated
)
but should be
permission_classes = (
permissions.IsAuthenticated,
# ^
# a comma here
)
So do not forget to look for other classes with permissions. I hope it will help someone.
As a reference for other people who might be searching here, this could be an issue too..
from django.contrib.auth.models import User
from rest_framework.generics import UpdateAPIView
from .serializers import UserSerializer
class UpdateView(UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = IsAuthenticated
Should change to:
from django.contrib.auth.models import User
from rest_framework.generics import UpdateAPIView
from .serializers import UserSerializer
class UpdateView(UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
#permission_classes((AllowAny,))
You have to ensure the comma
Junst in case this also can be solution. At least solved my issue
Just to complete #ihafurr's answer.
permission_classes shall be iterable because the variable is called by :func:viewsets.ModelViewSet.get_permission being (https://www.cdrf.co/3.12/rest_framework.viewsets/ModelViewSet.html):
def get_permissions(self):
return [permission() for permission in self.permission_classes]
Changing the last line of such method to the following could overcome the iterability requirement.
return [permission() for permission in self.permission_classes] if isinstance(self.permission_classes], Iterable) else [self.permission_classes]
where Iterable comes from
try:
from collections.abc import Iterable # for Python >= 3.6
except ImportError:
from collections import Iterable
I was facing the same problem and I was able to solve with this simple step
#permission_classes([IsAuthenticated])
so yeah, just put the method under the permission module in a bracket and you are good to go, hope it helps

valueerror invalid literal for int () with base 10 django in migrate, when deploying django project in heroku

models.py
from __future__ import unicode_literals
from django.db.models.signals import post_save
from django.db import models
# Create your models here.
from django.contrib.auth.models import User
class Friend(models.Model):
users = models.ManyToManyField(User)
current_user = models.ForeignKey(User, related_name = 'owner',null=True)
#classmethod
def make_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user = current_user
)
friend.users.add(new_friend)
#classmethod
def lose_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user = current_user
)
friend.users.remove(new_friend)
class Post(models.Model):
post=models.CharField(max_length=500)
user=models.ForeignKey(User)
data = models.DateTimeField(auto_now=True)
class UserProfileManager(models.Manager):
def queryset(self):
return super(UserProfileManager,self).get(queryset).filter(city='surat')
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100,default='')
city = models.CharField(max_length=100,default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
image = models.ImageField(upload_to='profile_image',blank=True)
surat = UserProfileManager()
def __str__(self):
return self.user.username
def create_profile(sender,**kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile,sender=User)
views.py
from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.contrib.auth.forms import UserCreationForm
from tutorial import views
from accounts.forms import Registrationform,EditProfileForm
from django.contrib.auth.forms import UserChangeForm,PasswordChangeForm
from django.contrib.auth.models import User
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.decorators import login_required
from django.views.generic import TemplateView
from .forms import HomeForm
from .models import Post,Friend
class HomeView(TemplateView):
template_name = 'accounts/home.html'
def get(self,request):
form = HomeForm()
posts=Post.objects.all()
users = User.objects.exclude(id=request.user.id)
friend =Friend.objects.get(current_user=request.user)
friends = friend.users.all()
args={
'form':form,'posts':posts,'users':users,'friends': friends
}
return render(request,self.template_name, args)
def post(self,request):
form = HomeForm(request.POST)
if form.is_valid():
post=form.save(commit=False)
post.user=request.user
post.save()
text =form.cleaned_data['post']
form = HomeForm()
return redirect('accounts:home')
args = {'form' : form,'text' : text}
return render(request, self.template_name,args)
def change_friends(request, operation, pk):
new_friend = User.objects.get(pk=pk)
if operation == 'add':
Friend.make_friend(request.user, new_friend)
elif operation == 'remove':
Friend.lose_friend(request.user, new_friend)
return redirect ('accounts:home')
def register(request):
if request.method == "POST":
form = Registrationform(request.POST)
if form.is_valid():
form.save()
return redirect('/accounts')
else:
return HttpResponse('please fill all the fields and make sure new password must be match')
else:
form = Registrationform()
args={'form' : form}
return render(request,'accounts/reg_form.html',args)
#login_required
def view_profile(request,pk=None):
if pk:
user = User.objects.get(pk=pk)
else:
user = request.user
args = {'user' : user}
return render(request,'accounts/profile.html',args)
#login_required
def edit_profile(request):
if request.user.is_authenticated():
#<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
if request.method=="POST":
form = EditProfileForm(request.POST,instance=request.user)
if form.is_valid():
form.save()
return redirect('/accounts/profile')
else:
return HttpResponse("please go back and write correct values")
else:
form = EditProfileForm(instance=request.user)
args = {'form' : form}
return render(request,'accounts/edit_profile.html',args)
else:
HttpResponse("hllo")
return redirect('/accounts/login')
#login_required
def change_password(request):
if request.user.is_authenticated():
if request.method == "POST":
form = PasswordChangeForm(data=request.POST,user=request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
return redirect('/accounts/profile')
else:
return HttpResponse("password does not match,go back and try again")
else:
form = PasswordChangeForm(user=request.user)
args = {'form' : form}
return render(request,'accounts/change_password.html',args)
else:
return redirect ('/accounts/login')
form.py
from django.contrib.auth.forms import UserCreationForm,UserChangeForm
from django.contrib.auth.models import User
#from django.forms import RegistrationForm,EditProfileForm
from django import forms
from accounts.models import Post
class HomeForm(forms.ModelForm):
post = forms.CharField(widget=forms.TextInput(
attrs={
'class':'form-control',
'placeholder' : 'write a post'
}
))
class Meta:
model = Post
fields = ('post',)
class Registrationform(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'password1',
'password2',
)
def save(self,commit=True):
user=super(Registrationform,self).save(commit=False)
user.first_name= self.cleaned_data['first_name']
user.last_name=self.cleaned_data['last_name']
user.email=self.cleaned_data['email']
if commit:
user.save()
return user
class EditProfileForm(UserChangeForm):
#template_name = '/something/else'
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name',
'password'
)
and the error is
(.vEnv) jayu#broadwell-gt2:~/Desktop/tutorial$ heroku run python manage.py migrate
› Warning: heroku update available from 7.0.82 to 7.0.83
Running python manage.py migrate on ⬢ jaysuthar... up, run.5398 (Free)
/app/.heroku/python/lib/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
""")
Operations to perform:
Apply all migrations: accounts, contenttypes, auth, admin, sessions
Running migrations:
Rendering model states... DONE
Applying accounts.0002_auto_20180514_0523...Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/management/__init__.py", line 350, in execute_from_command_line
utility.execute()
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/management/__init__.py", line 342, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/management/base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/management/base.py", line 399, in execute
output = self.handle(*args, **options)
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 200, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/migrations/executor.py", line 92, in migrate
self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/migrations/executor.py", line 121, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/migrations/executor.py", line 198, in apply_migration
state = migration.apply(state, schema_editor)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/migrations/migration.py", line 123, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/migrations/operations/fields.py", line 201, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 482, in alter_field
old_db_params, new_db_params, strict)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 564, in _alter_field
old_default = self.effective_default(old_field)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 210, in effective_default
default = field.get_db_prep_save(default, self.connection)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 728, in get_db_prep_save
prepared=False)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 720, in get_db_prep_value
value = self.get_prep_value(value)
File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1853, in get_prep_value
return int(value)
ValueError: invalid literal for int() with base 10: ''
Django keeps throwing the following when I deploying project (error is in migrate time when i run heroku run python manage.py migrate)
ValueError: invalid literal for int() with base 10: ''
i want to deploy this project on heroku, it successfully run till
git push heroku master --forc
but when i migrate database with this command :
heroku run python manage.py migrate
it gives error of valueerror.
where i did mistake ?
If you can provide any help I would greatly appreciate it.
EDIT :
accounts.0002_auto_20180514_0523 file :
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2018-05-14 05:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='phone',
field=models.IntegerField(default=0),
),
]
Obviously in it's first version your UserProfile's "phone" field was a CharField defaulting to the empty string. Changing an existing field's type requires a three-steps migrations: first create a new field with the desired type, create and apply the migration, then create a datamigration that will copy original data to the new field with proper transformations, error handling etc, and finally delete the original field (create and apply the migration).
BUT : in your case, making this field an integer is just plain wrong. A phone number is NOT an integer. First because you cannot add, substract, multiply or divide phone numbers, then because a phone number can contain non-numeric characters too (cf international phone numbers formats).
Thinking that everything made of numeric characters should be an int is a common beginner mistake (just like using floats instead of decimals for prices storage and calculations). When in doubt, ask yourself whether applying mathematical operations would make sense...

Django AssertionError at url

While learning Django rest framework, I got a AssertionError at /tasks/1 error
Expected view TaskDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the .lookup_field attribute on the view correctly.
My model.py
class Task(models.Model):
owner=models.ForeignKey('auth.User',related_name='tasks')
completed=models.BooleanField(default=False)
title=models.CharField(max_length=100)
description=models.TextField()
serializer.py
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
read_only=('owner.username',)
fields=('title','description','completed','owner.username')
permission.py
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method is SAFE_METHODS:
return True
return obj.owner==request.user
views.py
class TasksMixins(object):
queryset = Task.objects.all()
serializer_class=TaskSerializer
permission_classes=(IsOwnerOrReadOnly,)
def pre_save(self,obj):
obj.owner=self.request.user
class TaskList(TasksMixins,ListCreateAPIView):
pass
class TaskDetail(TasksMixins,RetrieveUpdateDestroyAPIView):
pass
Urls.py
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^tasks/$', views.TaskList.as_view(), name='task_list'),
url(r'^tasks/(?P<id>[0-9]+)$', views.TaskDetail.as_view(), name='task_detail')
]
Traceback
Traceback (most recent call last):
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/rest_framework/generics.py", line 286, in get
return self.retrieve(request, *args, **kwargs)
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 56, in retrieve
instance = self.get_object()
File "/home/amogh/PycharmProjects/env_1.9/local/lib/python2.7/site-packages/rest_framework/generics.py", line 93, in get_object
(self.__class__.__name__, lookup_url_kwarg)
AssertionError: Expected view TaskDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
When ever I navigate to the link I get this error
Any help is much appreciated...Thanks in advace
error image
If you want to target by 'pk', just rename id -> pk into your url.py:
url(r'^tasks/(?P<pk>[0-9]+)$', views.TaskDetail.as_view(), name='task_detail')
If you want to target by other field than pk,, you have to adjust the url.py, the view.py AND the serializer.py precising a lookup_field (that can be Nested) for example, it could be for you.
url.py:
url(r'^tasks/(?P<owner__username>[0-9]+)$', views.TaskDetail.as_view(), name='task_detail')
view.py:
class TasksMixins(object):
queryset = Task.objects.all()
serializer_class=TaskSerializer
permission_classes=(IsOwnerOrReadOnly,)
lookup_field = 'owner__username'
serializer.py
class TaskSerializer(serializers.ModelSerializer):
owner = serializers.SlugRelatedField(slug_field='username',many=False, read_only=True)
class Meta:
model = Task
fields='__all__'
lookup_field = 'owner__username'

Categories