How to override admin save_model method - python

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)

Related

AttributeError: 'property' object has no attribute 'copy' - while trying to get object list in Django Rest

To practice my Django skills i try to make simple module that should work more or less like Admin site in Django. It should gather all Models from Application, list them and show every object from each Model. i try to do is using Django Rest Framework.
Here is my views.py. I have 2 views. The api_root listens all models but it also sends params-models_names to another view 'model_view'. The ModelViewSet should list all objects from particular model.
class ModelsViewSet(viewsets.ModelViewSet):
def get_serializer(self, *args, **kwargs):
serializer_name = '{model_name}Serializer'.format(
model_name=self.kwargs.get('name').split(".")[1]
)
return getattr(serializers, serializer_name)
def get_model(self):
"""methods return model based on name kwargs
:return:
"""
return apps.get_model(self.kwargs.get('name'))
def get_queryset(self):
return self.get_model().objects.all()
def get_object(self):
return self.get_model().objects.get(pk=self.kwargs.get('pk'))
#api_view(['GET'])
def api_root(request, format=None):
return Response([reverse(
viewname='model_view',
kwargs={'name': i._meta.label}) for i in apps.get_models()])
Here is my serializers.py. In this file serializers classes are dynamically build. Each class is built on the basis of the model from django.apps.
from django.apps import apps
from rest_framework import serializers
from admin_site import serializers as m
from . import models
app_models = apps.get_models()
for item in app_models:
name = "{}Serializer".format(item.__name__)
class Meta(type):
model = item
fields = '__all__'
m.__dict__[name] = type(name, (serializers.ModelSerializer,), {})
m.__dict__[name].__metaclass__ = Meta
And finally here is my my_app.urls.py file. I think that maybe the problem is that ModelSetView isn't registered using DefaultRouter() but on the other hand i need to pass param to urlpattern. I don't know
urlpatterns = [
url(r'^$', views.api_root),
url(r'^model/(?P<name>[\w\-\.]+)/$',
views.ModelsViewSet.as_view({'get': 'list', 'put':'update'}), name='model_view'),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Everything is fine when i'm on api_root, i can see list of models. But when i add to root url /model/auth.User/ i get this error:
Traceback (most recent call last):
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/django/template/response.py", line 107, in render
self.content = self.rendered_content
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/rest_framework/response.py", line 72, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/rest_framework/renderers.py", line 716, in render
context = self.get_context(data, accepted_media_type,
renderer_context)
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/rest_framework/renderers.py", line 650, in get_context
raw_data_put_form = self.get_raw_data_form(data, view, 'PUT',
request)
File "/home/wojjak/Projects/envs/taskenvv/lib/python3.6/site-
packages/rest_framework/renderers.py", line 565, in get_raw_data_form
data = serializer.data.copy()
AttributeError: 'property' object has no attribute 'copy'
Any clue what can i do to accomplish my task and avoid this error?
override get_serializer_class() not get_serializer()

AttributeError at /notify/notify/ 'UserNotifications' object has no attribute 'user'

I am trying to make a notifications app. I have a middle that collects info about the action the user should be notified about and in the view that handles the action it automatically creates an instance in the UserNotification model. This is all working. Now, if a user's post gets liked by another user, that actions needs to be displayed on the notifications page. However, I obviously don't want any one use to be able to see every notification that is being created on the site, but rather only the notifications that are created by their posts.
I am running into an issue with the view and filtering the notifications based on the current user. More specifically, I am getting this error:
AttributeError at /notify/notify/
'UserNotifications' object has no attribute 'user'
With traceback:
Traceback (most recent call last):
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 56, in dispatch
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/anaconda3/envs/dev/lib/python3.6/site-packages/django/views/generic/list.py", line 160, in get
self.object_list = self.get_queryset()
File "/Users/garrettlove/Desktop/evverest/notify/views.py", line 30, in get_queryset
return UserNotification.objects.filter(user=request.user)
Here is my view pertaining to this:
// Bunch of imports are all here
User = get_user_model()
class UserNotifications(LoginRequiredMixin,ListView):
login_url = 'account_login'
model = UserNotification
template_name = 'notify/usernotification_list.html'
context_object_name = 'notifies'
paginate_by = 25
def get_queryset(request):
return UserNotification.objects.filter(user=request.user)
Here is my UserNotification model:
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
User = get_user_model()
# Create your models here.
class UserNotification(models.Model):
user = models.ForeignKey(User,related_name='user',null=True)
post = models.ForeignKey('feed.UserPost',related_name='post')
timestamp = models.DateTimeField(auto_now_add=True)
notify_type = models.CharField(max_length=6)
read = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
def get_queryset(self):
return UserNotification.objects.filter(user=self.request.user)

Where has cleaned_data vanished in Django 1.11?

I have created an inlineformset_factory as below :
formset = inlineformset_factory(Author, Book, form=BookForm,
formset=BaseBookFormSet,
can_order=False, can_delete=True,
extra=1, fields=('id', name)
)
BookForm is as below:
class BookForm(forms.ModelForm):
name = forms.Charfield(required=True)
def __init__(self, *args, **kwargs):
super(BookForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
Field("id", type="hidden"),
Field("name"),
Field("DELETE")
)
)
class Meta:
model = Book
fields = ('id', 'name')
def clean_name(self):
book_name = self.cleaned_data['name']
try:
book = Book.objects.get(name=book_name)
return book
except:
return book_name
def clean(self):
cleaned_data = super(BookForm, self).clean()
... other operations on cleaned_data ...
def has_changed(self):
changed = super(BookForm, self).has_changed()
cleaned_data = self.clean()
... other code here ...
This is throwing an error on submitting the form :
Exception Type: AttributeError
Exception Value: 'BookForm' object has no attribute 'cleaned_data'
when formset.is_valid() is called in views.py. Traceback first shows the line in has_changed where the self.clean is being called, and then the line in clean() where the super clean is being called.
This used to work fine in django 1.10.
When I tried printing dir(self) in Django 1.10 it does show 'cleaned_data' as one of the attributes where as in Django 1.11 it does not.
Where has the 'cleaned_data' vanished in Django 1.11?
EDIT: Adding traceback:
Traceback (most recent call last):
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/vagrant/test_os/inventory/views.py", line 297, in post
if formset.is_valid():
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 321, in is_valid
self.errors
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 295, in errors
self.full_clean()
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/formsets.py", line 345, in full_clean
if not form.has_changed():
File "/vagrant/test_os/inventory/forms.py", line 220, in has_changed
cleaned_data = self.clean()
File "/vagrant/test_os/inventory/forms.py", line 177, in clean
cleaned_data = super(BookForm, self).clean()
File "/home/vagrant/venv/local/lib/python2.7/site-packages/django/forms/models.py", line 344, in clean
return self.cleaned_data
AttributeError: 'BookForm' object has no attribute 'cleaned_data'
Formsets were fixed in 1.11 (in #26844) to ignore empty forms when validating the minimum number of forms. As a side-effect, formsets now call form.has_changed() on each form before validating the form. Django expects form.has_changed() to be safe to call before the form is validated, and the default implementation is indeed safe to call.
You have overridden form.has_changed() to call self.clean(), which now happens before the form is validated. Since form.clean() requires that the form is validated, this fails.
Since form.full_clean() actually calls self.has_changed(), you can't simply validate the form from within form.has_changed(). You don't show what you do in has_changed(), but it would most likely be a good idea to put this code elsewhere.

Token based authentication with Django REST Framework

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

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