Instead of using django's auth module I've used my own and already regret it a lot.
In an effort to rectify the situation, I'm trying to migrate the data from my User model to django.auth.models.User.
I've created a data migration as follows:
def forwards(self, orm):
"""Migrate user information from mooi User model to auth User model."""
OldUser = orm['mooi.User']
User = orm['auth.User']
Profile = orm['mooi.Profile']
oldUsers = OldUser.objects.all()
for oldUser in oldUsers:
newUser = User.objects.create_user(username=oldUser.id, email=oldUser.email, password=oldUser.password)
# ...more irrelevant code follows...
When I run the migration, I get this error (traceback):
#...irrelevant traceback precedes...
File "[projdir]/mooi/migrations/0005_from_mooi_users_create_auth_users_with_profiles.py", line 18, in forwards
newUser = User.objects.create_user(username=oldUser.id, email=oldUser.email, password=oldUser.password)
File "[virtual_env_dir]lib/python2.6/site-packages/south/orm.py", line 397, in __getattr__
return getattr(self.real, name)
AttributeError: 'Manager' object has no attribute 'create_user'
Upon further investigation, I discovered that the Manager
that was being referred to was of time south.orm.NoDryRunManager
which explains the error.
Now, the reason I even need create_user
is to create a password hash that django.contrib.auth
will understand.
Having said all that, how do I go about doing this? What's the most elegant solution given the hole I'm in?!
Thanks in advance.
Update 1
As suggested by stevejalim, I tried to use User
's set_password(...)
as follows:
newUser.set_password(raw_password=oldUser.password)
newUser.save()
However that failed with this error:
File "[projdir]/mooi/migrations/0005_from_mooi_users_create_auth_users_with_profiles.py", line 21, in forwards
newUser.set_password(raw_password=oldUser.password)
AttributeError: 'User' object has no attribute 'set_password'
I did find a hint in the south documentation which states that:
South doesn’t freeze every aspect of a model; for example, it doesn’t preserve new managers, or custom model methods, as these would require serialising the python code that runs those method (and the code that depends on, and so forth).
If you want custom methods in your migration, you’ll have to copy the code in, including any imports it relies on to work. Remember, however, for every import that you add, you’re promising to keep that import valid for the life for the migration.
I guess the question remains, what's the best/safest way of doing this? Copy the set_password(...)
method over? Create a function that hashes the password for me? Any other ideas?
Ok, it turns out that South doesn't freeze methods at all, so calling any model methods is of no use.
The way I solved this was by coping and modifying the code in contrib.auth that generates passwords.
Here's how the final migration looks like:
Why you don't just import what you need?.
I had the same problem and what I did was:
Why not make the
User
manually, then set the password after it has beensave()
d withnewUser.set_password()
? Yes, you'll need to hit the DB twice, but that's no great shakes.The whole point behind using the frozen ORM in migrations is to ensure that new changes don't interfere with old implementations. The auth app is part of
django.contrib
, and I doubt the functionality you're looking for has changed much in the past few releases, or is planned to change anytime soon. Aside from that, you're not going to be modifying the (auth) app or its models (right? right??). So it's pretty safe to say you don't need to use South's frozen version ofauth.User
; just import it normally and use it that way.