I want to log the last time my user has accessed the website and have implemented this middleware. It however does not store the most updated time.
middleware.py
class LastOnlineMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_request(self, request):
if request.user.is_authenticated():
request.user.profile.last_online = timezone.now()
request.user.profile.save()
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_online = models.DateTimeField(default=timezone.now)
It dose not work because process_request is not called in __call__ function.
You should change __call__ function like below.
def __call__(self, request):
self.process_request(request)
return self.get_response(request)
or to make LastOnlineMiddleware subclass of django.utils.deprecation.MiddlewareMixin.
If you use MiddlewareMixin, there is no need to define __init__ and __call__ function. You just needed to define process_request function written in the question.
Related
I want to add a dispatch method to some resource so I could use a wrapper decorator on it.
The issue is that it only works on the CRUD operations and wont go into the dispatch method on 'original' endpoints:
class SomeResource(SomeBaseResource):
class Meta(...): ...
def get_something_extra(self, request, **kwargs):
...
def patch_detail(self, request, **kwargs):
...
and the base resource:
class SomeBaseResource(ModelResource):
class Meta(...): ...
# the wrapper
#decorator_to_wrap_all_methods_with(...)
def dispatch(self, request_type, request, **kwargs):
logger.info('Enter')
response = super(SomeBaseResource, self).dispatch(request_type, request, **kwargs)
logger.info('Exit')
return response
So when I use patch request it is working as expected, but wont on calling the get_something_extra api.
How do I wrap ALL methods in resource?
A workaround solution is to add Middleware:
MIDDLEWARE = (
'my.basic.BaseMiddleware',
...
)
class BaseMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
#decorator_to_wrap_all_methods_with(...)
def __call__(self, request):
response = self.get_response(request)
return response
I am looking for the right directions to add a custom field in the HTTP response using middleware and access the custom field in the JavaScript front-end.
I am trying to implement this, but on receiving the response on the JavaScript side there is no field like "is_logged" in the body.
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
response = self.get_response(request)
response.body['is_logged'] = True
else:
response = self.get_response(request)
response.body['is_logged'] = False
return response
How would one create "new style" middleware, which fulfills an equivalent implementation to using the process_request() hook with the "old style"?
I've already adapted pre 1.10 middleware process_request() using MiddlewareMixin...
from django.utils.deprecation import MiddlewareMixin
class MyCustomMiddleware(MiddlewareMixin):
def process_request(self, request):
# My request logic
return response
I'd like to know how to do a "pure" >1.9 "new style" implementation. I tried doing so by implementing __init__() and __call__() like this without luck:
class MyCustomMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# My request logic
return response
Thanks.
Here an example...
class TimeStampMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
response = self.get_response(request)
return response
Now you can get the timestamp in every request from yours views! (is only an example)
I recently switched to class-based views in my Django app and want to use them as elegantly as possible. In the app, I have a comment system and, if permissions are matched, admins should be able to delete and/or publish/unpublish a comment. I wrote a RedirectView for that, including both functionality:
class CommentChangeView(RedirectView, SingleObjectMixin):
"""
A redirection that acts on a Comment. The url parameter
"action" is taken as a class function and executed.
"""
model = Comment
def get_redirect_url(self, pk):
"""
Redirect to the article page, always.
"""
return reverse('post', args=(self.object.post.slug,))
def get(self, *args, **kwargs):
"""
Here, it is decided what to execute.
"""
self.object = self.get_object()
func = getattr(self, kwargs.pop('action', None), None)
if callable(func):
func()
return super(CommentChangeView, self).get(*args, **kwargs)
#method_decorator(permission_required('blog.delete_comment'))
def delete(self):
"""
Delete the comment
"""
self.object.delete()
messages.success(self.request, 'Comment deleted.')
#method_decorator(permission_required('blog.change_comment'))
def toggle_publish(self):
"""
Toggle its publication state
"""
self.object.published = not self.object.published
self.object.save()
messages.success(self.request, 'Comment toggled.')
Now the thing is, I want the two actions to have different permissions - hence the different decorators. Usually, the dispatch function is decorated. The code above doesn't work, I am getting a TypeError. Without the decorators, it works perfectly.
How would I implement this case? Or should I separate the views for deletion and publication?
Here is the StackTrace of the TypeError:
Internal Server Error: /comment/toggle_publish/1/
Traceback (most recent call last):
File "/***/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/***/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/***/lib/python2.7/site-packages/django/views/generic/base.py", line 86, in dispatch
return handler(request, *args, **kwargs)
File "/***/blog/blog/views.py", line 186, in get
func()
File "/***/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper
return bound_func(*args, **kwargs)
TypeError: _wrapped_view() takes at least 1 argument (0 given)
Bibhas pointed me into the right direction, by more closely looking at the StackTrace. I was able to get it working by introducing one additional argument for the functions. This code works now:
class CommentChangeView(RedirectView, SingleObjectMixin):
"""
A redirection that acts on a Comment. The url parameter
"action" is taken as a class function and executed. It therefore
combines the delete and publish_comment functions (and, later, possibly)
more.
"""
model = Comment
def get_redirect_url(self, pk):
"""
Redirect to the article page, always.
"""
return reverse('post', args=(self.object.post.slug,))
def get(self, request, *args, **kwargs):
"""
Here, it is decided what to execute.
"""
self.object = self.get_object()
func = getattr(self, kwargs.pop('action', None), None)
if callable(func):
func(request)
return super(CommentChangeView, self).get(request, *args, **kwargs)
#method_decorator(permission_required('blog.delete_comment'))
def delete(self, request):
"""
Delete the comment
"""
self.object.delete()
messages.success(self.request, 'Comment deleted.')
#method_decorator(permission_required('blog.change_comment'))
def toggle_publish(self, request):
"""
Toggle its publication state
"""
self.object.published = not self.object.published
self.object.save()
messages.success(self.request, 'Comment toggled.')
Following this tutorial:
http://django-rest-framework.org/tutorial/1-serialization.html
through http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html
I have this code:
# models.py
class Message(BaseDate):
"""
Private Message Model
Handles private messages between users
"""
status = models.SmallIntegerField(_('status'), choices=choicify(MESSAGE_STATUS))
from_user = models.ForeignKey(User, verbose_name=_('from'), related_name='messages_sent')
to_user = models.ForeignKey(User, verbose_name=_('to'), related_name='messages_received')
text = models.TextField(_('text'))
viewed_on = models.DateTimeField(_('viewed on'), blank=True, null=True)
# serialisers.py
class MessageSerializer(serializers.ModelSerializer):
from_user = serializers.Field(source='from_user.username')
to_user = serializers.Field(source='to_user.username')
class Meta:
model = Message
fields = ('id', 'status', 'from_user', 'to_user', 'text', 'viewed_on')
# views.py
from permissions import IsOwner
class MessageDetail(generics.RetrieveUpdateDestroyAPIView):
model = Message
serializer_class = MessageSerializer
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (permissions.IsAuthenticated, IsOwner)
# permissions.py
class IsOwner(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit or delete it.
"""
def has_permission(self, request, view, obj=None):
# Write permissions are only allowed to the owner of the snippet
return obj.from_user == request.user
# urls.py
urlpatterns = patterns('',
url(r'^messages/(?P<pk>[0-9]+)/$', MessageDetail.as_view(), name='api_message_detail'),
)
Then opening the URL of the API i get this error:
**AttributeError at /api/v1/messages/1/
'NoneType' object has no attribute 'from_user'**
Traceback:
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/views/generic/base.py" in view
48. return self.dispatch(request, *args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
77. return view_func(*args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in dispatch
363. response = self.handle_exception(exc)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in dispatch
351. self.initial(request, *args, **kwargs)
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in initial
287. if not self.has_permission(request):
File "/var/www/sharigo/python/lib/python2.6/site-packages/rest_framework/views.py" in has_permission
254. if not permission.has_permission(request, self, obj):
File "/var/www/sharigo/sharigo/apps/sociable/permissions.py" in has_permission
17. return obj.from_user == request.user
Exception Type: AttributeError at /api/v1/messages/1/
Exception Value: 'NoneType' object has no attribute 'from_user'
It seems like None is being passed as the value for the parameter "obj" to isOwner.has_permission().
What am I doing wrong? I think i followed strictly the tutorial.
When has_permission() is called with obj=None it's supposed to return whether the user has permission to any object of this type. So you should handle the case when None is passed.
Your code should be something like:
def has_permission(self, request, view, obj=None):
# Write permissions are only allowed to the owner of the snippet
return obj is None or obj.from_user == request.user
Use function has_object_permission instead of has_permission.
ex:
def has_object_permission(self, request, view, obj=None):
return obj.from_user == request.user
and call function check_object_permissions inside get_object in views
def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj