Overriding contrib.auth User save()

1,708 views
Skip to first unread message

Paddy Joy

unread,
Nov 26, 2008, 5:54:19 AM11/26/08
to Django users
I would like to override the save() method on the contrib.auth User
model so that I can run a routine when a user is created/modified.

Is this possible or do I need to use a signal? I have tried overriding
the User model like this but it never seems to call my code:

from django.contrib.auth.models import User

# Override User model
class User(models.Model):

def save(self):

# Do something here
myroutine()
super(User, self).save()

Can anyone help?

Paddy

Alex Koshelev

unread,
Nov 26, 2008, 6:01:17 AM11/26/08
to django...@googlegroups.com
Of course you can monkey-patch the User model but the better way is to use signals pre_ or post_save

sergioh

unread,
Nov 26, 2008, 8:39:52 AM11/26/08
to Django users
Signals are the better way to achieve. You usually override the save
method when you need to define something related with the model
itself, but in many cases signals are the better way to notify some
function to do something if a model change (after save)

def your_function(sender, instance, created=False, **kwargs):
# your tasks

models.signals.post_save.connect(your_function, sender=User) #this
relate your User model with the signal


regards,

Sergio Hinojosa

On Nov 26, 7:01 am, "Alex Koshelev" <daeva...@gmail.com> wrote:
> Of course you can monkey-patch the User model but the better way is to use
> signals pre_ or post_save
>

Paddy Joy

unread,
Nov 27, 2008, 11:11:02 AM11/27/08
to Django users
Thanks for the tips, signals would work except I need access to the
raw password when users are created.

On further inspection it seems I would need to override the
UserManager, I know I can extend it with more methods but I don't
think I can override it.

Paddy

bruno desthuilliers

unread,
Nov 27, 2008, 11:59:21 AM11/27/08
to Django users


On 27 nov, 17:11, Paddy Joy <paddy...@gmail.com> wrote:
> Thanks for the tips, signals would work except I need access to the
> raw password when users are created.
>
> On further inspection it seems I would need to override the
> UserManager,

On even further inspection, you may in fact want to override
User.set_password !-)

> I know I can extend it with more methods but I don't
> think I can override it.

As Alex said, you can always - I mean, as a _last_ resort -
monkeypatch it:

# mymodel.py
from auth.models import UserManager
_create_user = UserManager.create_user
def my_create_user(self, username, email, password=None):
# do whatever here
# and eventually remember to call the original method
return _create_user(self, username, email, password)

UserManager.create_user = my_create_user

# et voilà.

sergioh

unread,
Nov 27, 2008, 10:28:00 PM11/27/08
to Django users
Maybe you could override the save method in a New User Model Form:

save_model(self, request, obj, form, change)

So you can:

admin.site.unregister(User)
admin.site.register(User, NewModelForm)

http://docs.djangoproject.com/en/dev/ref/contrib/admin/

I hope this could help you!

And finally the other way i usually use is extend a new Client Model
from User, so i have a plenty access to the User Model
and also from the request i get it through request.user.client and i
override the save method for it.

Regards,

Sergio Hinojosa

On Nov 27, 12:59 pm, bruno desthuilliers

Paddy Joy

unread,
Nov 28, 2008, 3:45:08 AM11/28/08
to Django users
Thanks however I'm guessing:
>
> admin.site.unregister(User)
> admin.site.register(User, NewModelForm)
>

will only work in the admin site? Not actually using the admin site at
the moment but would nice to have something that would work globally.


I nearly have the monkey patch working however I'm getting the
following error, any idea?

>>> from django.contrib.auth.models import UserManager
>>> a=UserManager()
>>> a.create_user(username='sdf', email='s...@sdf.com', password='222')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/var/django/mysite/../mysite/hosting/models.py", line 166, in
my_create_user
return _create_user(self, username, email, password)
File "/usr/lib/python2.5/site-packages/django/contrib/auth/
models.py", line 100, in create_user
user = self.model(None, username, '', '', email.strip().lower(),
'placeholder', False, True, False, now, now)
TypeError: 'NoneType' object is not callable

bruno desthuilliers

unread,
Nov 28, 2008, 7:02:43 AM11/28/08
to Django users
On 28 nov, 09:45, Paddy Joy <paddy...@gmail.com> wrote:
> Thanks however I'm guessing:
>
>
>
> > admin.site.unregister(User)
> > admin.site.register(User, NewModelForm)
>
> will only work in the admin site?

Yes.

> Not actually using the admin site at
> the moment but would nice to have something that would work globally.
>
> I nearly have the monkey patch working however I'm getting the
> following error, any idea?
>
> >>> from django.contrib.auth.models import UserManager
> >>> a=UserManager()
> >>> a.create_user(username='sdf', email='...@sdf.com', password='222')
>
> Traceback (most recent call last):
> File "<console>", line 1, in <module>
> File "/var/django/mysite/../mysite/hosting/models.py", line 166, in
> my_create_user
> return _create_user(self, username, email, password)
> File "/usr/lib/python2.5/site-packages/django/contrib/auth/
> models.py", line 100, in create_user
> user = self.model(None, username, '', '', email.strip().lower(),
> 'placeholder', False, True, False, now, now)
> TypeError: 'NoneType' object is not callable

Your UserManager instance is not connected to any model, so it's model
attribute is None. Manager classes are meant to be used thru model
classes, not directly.

IOW, you want:

from django.contrib.auth.models import User
user = User.objects.create_user(username='sdf', email='...@sdf.com',
password='222')

HTH

sergioh

unread,
Nov 28, 2008, 8:39:35 AM11/28/08
to Django users


On Nov 28, 8:02 am, bruno desthuilliers
<bruno.desthuilli...@gmail.com> wrote:
> On 28 nov, 09:45, Paddy Joy <paddy...@gmail.com> wrote:
>
> > Thanks however I'm guessing:
>
> > > admin.site.unregister(User)
> > > admin.site.register(User, NewModelForm)
>
> > will only work in the admin site?
>
> Yes.

Actually as is a Form you are able to use it not just in the admin
section, you could override the fields or add as many fields as you
want, but you will need to define the validation methods for those new
fields and also the save method, you could use it in any view and pass
it to a template for rendering.

An actually monkey patch may cause you problems for future versions,
and if you are planing to have many applications sharing your django,
it will cause you problems. I think it you could find a better
solution, just keep going.

Kind Regards,

Sergio Hinojosa

sergioh

unread,
Nov 28, 2008, 9:36:47 AM11/28/08
to Django users
I did not notice you were trying to override in a wrong way, sorry
about that.

Actually for override the user model you need to:

class CustomUser(User):
#your new fields, DRY user fields
objects = MyCustomManager()

class MyCustomManager(models.Manager):
def create_mycustom_user(.................):
self.create(.......#user fields and your new custom
fields#........)
self.set_password('222')
self.save()
Reply all
Reply to author
Forward
0 new messages