When I save a User model, I would like to check if it has a username.
Therefore I wrote this pre_save:
#receiver(pre_save, sender=User)
def validate_user(sender, instance, **kwargs):
if len(instance.username) <= 5: raise Exception("Username too short")
Now in my testing method I would like to test this exception:
def test_user_no_username(self):
u = User.objects.create()
self.assertRaises(Exception, u.save())
The test fails. Why?
assertRaises is kind of a specific exception - as a second argument you should pass a callable:
assertRaises(exception, callable, *args, **kwds)
In other words, don't call u.save():
self.assertRaises(Exception, u.save)
Also, you should really think about having custom exceptions or using built-in Django validation errors instead of raising and catching the broad Exception.
Related
I recently upgraded Django from 2.0.7 to 2.1.1, a new error occurs in which I get this error 'functools.partial' object has no attribute '__name__'.
I'd like to understand if my fix is right and what caused this new error to happen, I couldn't find anything on the django release notes related to this issue, maybe I missed it.
decorators.py
def auth0_login_required(function):
def wrap(request, *args, **kwargs):
if request.isAuthenticated or request.user.is_staff:
pass
else:
raise Http404()
return function(request, *args, **kwargs)
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__ # ERROR HERE
return wrap
How it is used, views.py:
#method_decorator(auth0_login_required, name='dispatch')
class Dashboard(View):
...
For the fix I just removed wrap.__name__ = function.__name__, but I'm not sure if it'll break something else.
Rather than manually copy things across, use the #functools.wraps() decorator to handle this for you:
from functools import wraps
def auth0_login_required(function):
#wraps(function)
def wrap(request, *args, **kwargs):
if request.isAuthenticated or request.user.is_staff:
pass
else:
raise Http404()
return function(request, *args, **kwargs)
return wrap
The #wraps() decorator (via the functools.update_wrapper() function it calls knows how to handle functools.partial objects correctly (or rather, it can handle the fact that functools.partial objects have no __name__ attribute).
It's fine that the wrapped functools.partial() object found on the View class doesn't have a __name__ attribute, what's not fine is that you then don't copy that attribute at all even when you are decorating functions that do have the attribute. If you don't want to use #wraps() you'd have to manually copy the attribute across and handle the exception yourself:
try:
wrap.__name__ = function.__name__
except AttributeError:
pass
try:
wrap.__doc__ = function.__doc__
except AttributeError:
pass
but take into account that this doesn't copy the __qualname__, __module__ and __annotations__ attributes, doesn't handle any custom attributes set on function (which other decorators might rely on). #functools.wraps() does take care of all of those, plus it sets the __wrapped__ attribute on the decorator wrapper function that would let you unwrap the decorator again.
Alright I have a method called no_m in the user class and i've not written a decorator before, but basically I need to redirect the user to another URL if they pass this. I have created a file called decorators.py in a dir called accounts and i'm guessing the decorator is imported correctly, however I cannot get it to work. Heres what I have:
def no_m(view_func):
def _wrapped_view_func(request, *args, **kwargs):
try:
if request.user.is_m():
# quick test
return HttpResponseRedirect('http://google.com')
else:
return view_func(request, *args, **kwargs)
except:
return _wrapped_view_func
All it needs to do is redirect users if they pass that test, I don't know what the URL needs to be yet so it's just google for now. Any ideas? Like I said, i've not written decorators before so it's all new to me. Thankyou.
Another thought: would it be possible to render a template page?
You're missing a step in the decorator, or rather you have a step confused. It's the outer function that must return the inner function (_wrapped_view_func), and it must always do so: that's what takes the place of the original function when it is called.
I'm not sure what the except clause is there for. Apart from it always being a bad idea to use a blank except - that catches everything, including things like ctrl-c - exceptions in Django functions are usually handled by the middleware, rather than the decorator. I would just remove it.
So the code should be:
def no_m(view_func):
def _wrapped_view_func(request, *args, **kwargs):
if request.user.is_m():
# quick test
return HttpResponseRedirect('http://google.com')
else:
return view_func(request, *args, **kwargs)
return _wrapped_view_func
I am trying to extend a class whose name is 'Account' (from django-user-accounts app) with my own 'snAccount' class, since I need to add some extra fields to each user account. The problem comes when I try to override the "factory" method (#classmethod) of the parent class with mine:
# Original method
#classmethod
def create(cls, request=None, **kwargs):
...
...
# Override attempt
#classmethod
def create(cls, request=None, **kwargs):
create_email = kwargs.pop("create_email", True)
user = kwargs.pop("user", None)
acc = Account.create(request, user, create_email)
x_account = cls(account, **kwargs)
x_account.save()
return x_account
The problem I have throws the following exception:
Django Version: 1.4.5
Exception Type: TypeError
Exception Value: create() takes at most 2 arguments (4 given)
Exception Location: /home/.../WebServices/models.py in create, line 27
... which I cannot understand since the definition of that method takes 2 implicit arguments and **kwargs in addition. What am I doing wrong? I do not have much experience with Python, as you might see...
You haven't actually used any keyword arguments.
acc = Account.create(request, user=user, create_email=create_email)
Given this Django code in my models.py:
class ClientManager(UserManager):
def create_user(self, *args, **kwargs):
raise(Exception)
client = Super(UserManager, self).create_user(*args, **kwargs)
return client
class Client(AbstractUser):
objects = ClientManager()
How come no exception is raised when I create a Client user from the admin?
I've tried many variations on that principle, but no create_user ever seems to be used apart from the model's __init__(). Adding an exception in django.contrib.auth.models.UserManager.create_user() method also leads to the user being created without raising an exception, which seems to indicate that I'm missing something big, here.
On views that allow updating/deleting objects, I need a decorator that verifies that the object to be edited belongs to a group(model "loja). Both defined in the url:
/[slug model loja--s_loja]/[viewname-ex:addmenu]/[object id--obj_id]
Because the model of the object can vary, the decorator the model of the object as an argument. Every model that may be passed as an argument has a foreign key to the model "loja" named loja.
The decorator:
def acesso_objecto(modelo):
def wrap(f):
def wrapper(*args, **kwargs):
s_loja = kwargs['s_loja']
obj_id = kwargs['obj_id']
objecto = get_object_or_404(modelo, pk=obj_id)
loja = get_object_or_404(Loja, slug=s_loja)
if objecto.loja is not loja:
raise Http404
else:
return f(*args, **kwargs)
return wrapper
return wrap
Basically, unless the group "loja" and the object exists and the object belongs to that group a 404 error should be raised.
Without the decorator the view works fine, but the decorator always raises 404 because the if statement is always true even when it shouldn't be. If I use the loja.id or loja.slug for verification it works as THEY ARE related, but this function always seems to fail and I have no idea why.
Replace is not with !=.
not loja is evaluating to True, and the if statement is testing the equality between objecto.loja and True.