问题
With Django 1.5 and the introduction of custom user models the AUTH_PROFILE_MODULE
became deprecated. In my existing Django application I use the User
model and I also have a Profile
model with a foreign key to the User
and store other stuff about the user in the profile. Currently using AUTH_PROFILE_MODULE
and this is set to 'app.profile'.
So obviously, my code tends to do lots of user.get_profile()
and this now needs to go away.
Now, I could create a new custom user model (by just having my profile model extend User
) but then in all other places where I currently have a foreign key to a user will need to be changed also... so this would be a large migration in my live service.
Is there any way - and with no model migration - and only by creating/overriding the get_profile()
function with something like my_user.userprofile_set.all()[0]
) somewhere?
Anyone out there that has gone down this path and can share ideas or experiences?
If I where to do this service again now - would obviously not go this way but with a semi-large live production system I am open for short-cuts :-)
回答1:
Using a profile model with a relation to the built-in User
is still a totally legitimate construct for storing additional user information (and recommended in many cases). The AUTH_PROFILE_MODULE
and get_profile()
stuff that is now deprecated just ended up being unnecessary, given that built-in Django 1-to-1 syntax works cleanly and elegantly here.
The transition from the old usage is actually easy if you're already using a OneToOneField
to User
on your profile model, which is how the profile module was recommended to be set up before get_profile was deprecated.
class UserProfile(models.Model):
user = OneToOneField(User, related_name="profile")
# add profile fields here, e.g.,
nickname = CharField(...)
# usage: no get_profile() needed. Just standard 1-to-1 reverse syntax!
nickname = request.user.profile.nickname
See here if you're not familiar with the syntactic magic for OneToOneField
's that makes this possible. It ends up being a simple search and replace of get_profile()
for profile
or whatever your related_name
is (auto related name in the above case would be user_profile
). Standard django reverse 1-1 syntax is actually nicer than get_profile()
!
Change a ForeignKey to a OneToOneField
However, I realize this doesn't answer your question entirely. You indicate that you used a ForeignKey
to User
in your profile module rather than a OneToOne
, which is fine, but the syntax isn't as simple if you leave it as a ForeignKey
, as you note in your follow up comment.
Assuming you were using your ForeignKey
in practice as an unique foreign key (essentially a 1-to-1), given that in the DB a OneToOneField is just a ForeignKey field with a unique=True constraint, you should be able to change the ForeignKey
field to a OneToOneField
in your code without actually having to make a significant database migration or incurring any data loss.
Dealing with South migration
If you're using South for migrations, the code change from the previous section may confuse South into deleting the old field and creating a new one if you do a schemamigration --auto
, so you may need to manually edit the migration to do things right. One approach would be to create the schemamigration and then blank out the forwards and backwards methods so it doesn't actually try to do anything, but so it still freezes the model properly as a OneToOneField
going forward. Then, if you want to do things perfectly, you should add the unique constraint to the corresponding database foreign key column as well. You can either do this manually with SQL, or via South (by either editing the migration methods manually, or by setting unique=True
on the ForeignKey
and creating a first South migration before you switch it to a OneToOneField
and do a second migration and blank out the forwards/backwards methods).
来源:https://stackoverflow.com/questions/20613315/get-rid-of-get-profile-in-a-migration-to-django-1-6