django附加额外信息到user
django的用户模块提供了很好的用户管理,包括用户的注册和登录认证,但是发现user的模型中只包含了简单的几个数据段,如果我们想要其他的信息,比如用户的兴趣爱好,职业等,我们怎么办呢。
下面我找到一篇的很好的文章提到了,怎么做到这点。
Django User Profiles – Simple yet powerful
By
Alon Swartz –
35 comments | Latest by
dpbklyn
So you're building a web application, and using the excellent contrib.auth subsystem to manage user accounts. Most probably you need to store additional information about your users, but how? Django profiles to the rescue!
Django provides a lightweight way of defining a
profile object linked to a given user. The profile object can differ from project to project, and it can even handle different profiles for different sites served from the same database.
In a nutshell, using Django profiles consists of 3 steps:
- Define a model that holds the profile information.
- Tell Django where to look for the profile object.
- Create the user profile as needed.
Defining the user profile model
The only requirement Django places on this model is that it have a unique ForeignKey to the User model, and is called user. Other than that, you can define any other fields you like.
For our example, we'll create 2 user profile fields (url and company).
account/models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
url = models.URLField("Website", blank=True)
company = models.CharField(max_length=50, blank=True)
Tell Django about the profile object
Accessing a users profile is done by calling user.get_profile(), but in order to use this function, Django needs to know where to look for the profile object.
This is defined in the projects settings.py file.
AUTH_PROFILE_MODULE = "account.UserProfile"
Important note: The settings value is appname.modelname, and not
appname.models.modelname as you might expect. The reason for this is that Django is not doing a direct import, but using an internal model-loading function.
Once defined, and if the profile exists, accessing a users profile is simple.
foo/views.py
@login_required
def view_foo(request):
user_profile = request.user.get_profile()
url = user_profile.url
#OR
url = request.user.get_profile().url
Create the user profile as needed
Notice in the section above I mentioned "if the profile exists". This is because the
get_profile() function will raise a DoesNotExist exception if the profile does not exist.
One of the common solutions to this issue is to create the profile when a user is registered using a signal (see my post on
Django Signals).
Another option is catch the exception, and redirect the user to a profile creation form. You usually want to do this if the profile fields are mandatory.
My personal favorite though, is to have the profile created automatically when referenced, with the added bonus of being able to reference a users profile as
user.profile instead of user.get_profile()
account/models.py
...
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
...
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
To reiterate, including the above enables us to reference the users profile with cleaner code, and have it created if it does not exist.
foo/views.py
@login_required
def view_foo(request):
url = request.user.profile.url
Ever needed to store additional user information?
Post a comment!
Comments
Why do Django profiles exist
Why do Django profiles exist when you can just define another model with a foreign key to the user model? Is it simply to define a standard profiling system? It seems odd that it re-creates a profile model with a foreign key yet forces you to use a function
to retrieve it (get_profile) instead of just giving you: user.profile.
Thanks, Mike
I am sure django is powerful
I am sure django is powerful and quite useful. The applications in “contrib.” package are very tempting.Especially the tools for generating rss and atom feed.But django is not free from problem. It just isn’t effective enough. It lacks a bit on creating
boundary pushing models effectively. Is it possible to use sphinx for our documentation is this tool compatible with django? I have read some where piston is very useful in creating API’s. Is it so?
Are you a bot? If so, can you pass the turing test?
Most of the comments that try to take advantage of the Drupal comment external backlink are posted by automated spam bots. We usually delete those immediately. But your response is eerily relevant to the discussion so I suspect you may be a human.
Please don't take offense. As far as I'm concerned you're welcome to join the community even if you are a bot – so long as you can pass my turing test and respond appropriately.
TurnKey welcomes all sentient beings.
Nice. I like when
Nice. I like when administrators or moderators treat comments in such a way.
Well, it has been some time
Well, it has been some time since I have been looking out for something like this. I often indulge in building web applications and I too use the same subsystem contrib.auth for the purpose of managing my accounts. Things are really great, to be honest,
except for the fact that I have to store extra information regarding the users. Anyway, since I started using Django, things have really been great from then on! The fact that it provides a really easy way of defining things is why I found it handy!
creating the profile
Hi Alon,
What is the python-level code for creating users' profiles? In the shell, whenever I type "p=User.objects.get(username='xxxx').get_profile" followed by "p.attribute1", I receive a "'User' object has no attribute 'attribute1'.
Any suggestions for creating the profile to make sure this attribute "registers"? Thanks!
follow-up question
Hi again Alon, Thanks for your earlier reply. I'm getting back to Django after a long holiday vacation (I hope you enjoyed one too!), and I revisited your answer.
I think I figured out my problem, and I thought it may be helpful for others if I post this here. Also, I welcome your thoughts on my quick-and-dirty/DIY/band-aid fix.
I realized that setting up profiles according to your instructions doesn't actually create profiles for pre-existing users. So when typing "get_profile()" it always returned an error, even though I
knew the users existed and had attributes.
In response to my own question, I figured out how to create user profiles for pre-existing users. First is assigning the user object: "u=User.objects.get(username="xxxx")". Then you must type: "u.userprofile_set.get_or_create(field1=foo, field2=bar, attribute3=foobar)".
This creates the profile with the assigned field values.
Of course, this could all be done in a view. And it could also be re-coded to match your elegant suggestion. But this at least is how I got it to work code-level.
One question, though: do you know of a way to update the values once they're set?
Thoughts? Suggestions (other than for elegance)?
Thanks again, Alon!
creation error
Thank you for your explanations but what's the way to create a new custom user then ?
I guess I should first create the "normal" user (using User.objects.create_user(,,)) and then the extended one using the foreign key to the newly created user. When I'm using the shell to do it, I've got an error with the first command that the first of
my custom field is required…
Ok forgot what I said, I put
Ok forgot what I said, I put some code I found
here that I guess is wrong
I love the option of creating
I love the option of creating a user profile. It really makes a site look professional, and keeps out the riffraff. I don't develop anything without this option.
DatabaseError
Hello.
I have created user profile, but what about the additional table "maApp_userprofile" in my database ? The DatabaseError (1146, "Table 'myApp.myApp_userprofile' doesn't exist") is occurs. And "manage.py syncdb" does nothing. How this table must be created
?
still stuck….
Thanks for the useful post! Where I am still stuck is trying to figure out how to create test users through a command. For example, if I have an app:
accounts
models.py
management
commands
mycommand.py
and I follow your lead in models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
age=models.IntgerField(blank=True)
display_name=models.CharField(max_length=150)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
What would I put in mycommand.py to create a test user with a username of Bob, no age given, and a display name of Bob Smith? So far, everything I have tried han't actually resulted in the UserProfile which is attached to the user actually being updated
in the database.
Thanks,
William
back-end
Hey, (sorry for my english :-( )
Thanks for this posts !
I want to add the Field 'Bureau' the user.
I do the same things in your post ;)
But I don't have the field 'Bureau' in the back-end of the site ??!!
Steps to build user accounts
Hi Alon,
I've read quite a bit about creating users and it all seems to make sense until I go to make them myself. I find I am missing some crucial bit of information to make it all work.
Here is what I think I should do to set up a user accounts:
1. Create app called 'accounts'
2. In accounts/models.py, create a model for the 'base' user information; username, password, email
3. In accounts/models.py, create a second model for the detailed user information; first & last name, favourite colour, etc.
4. In accounts/views.py, create functions for new user registration, login, logout, etc.
5. In ../settings.py, set AUTH_PROFILE_MODULE = ('accounts.baseUser',)
6. In ../urls.py, link views to templates
7. In ../templates/registration/accounts make template files for login, etc.
Is step 2 correct or should this 'base' user model be handled by contrib.auth.models? In otherwords, do I just need to worry about making models for the extended information and link it to contrib.auth.models.User?
You may guess that I am new to Django and obj-oriented programming. I have gone through the Djangoproject.com. Can you share a link to an example where someone sets up the user models, registration, login from scratch as opposed to snippits that I have
to figure out how to reassemble?
steps to build user accounts
Thanks, Alon. Your response helps to clarify. I will reread.
Roland
models.ForeignKey(User) Causes Admin Error
Hi Alon,
I got rid of the user models I built before and am now relying on the built in user model. I built an app called msgboard that has the following model:
is that the 'author' line does not cause admin/msgboard/findmsg/add to fail; ie author shows up as a form item as it should.
models.ForeignKey(User) Causes Admin Error
Alon,
Very interesting. I created a new project from scratch to try it again and it worked this time. The problem, I believe, was that I corrupted the original project's admin site by attempting to define my own User models. I guess this causes irreparable corruption
or, at least, I don't know how to fix it.
Roland
The only problem with this is
The only problem with this is that there is no profile caching like with get_profile(). So if you were to do something like…
user.profile.some_field = some_value
user.profile.save()
the user profile would not be updated!
Django user registration system
I am very new to the Django. Can you help me to design a Django project which will create the user and their profiles. But I dont want to use default admin Django model. And these are accessable without admin login.
auto creation of the UserProfile
What do you think of the ForienKey approach in combonation with a "User" post_save creation of the "UserProfile"? The following app is pluggable and takes care of all of that for you.
Mind you that the UserProfile class still needs to be created by developers and the delete() method on the UserProfile has to be updated to delete any non-user FK, M2M … etc.
This the ForienKey approach recommended by James Bennette the release manager of Django.
I was facing problem of
I was facing problem of creating profile.But your instructions helped me a lot.Thanks.
UserProfiles in a second database
Hello!
I'm building Django app on top of an existing database (MS SQL). I have to access some existing data in that database, so as a UserProfile model I've used an exitsting table. Everything works as expected, but using MSSQL and Apache on Windows drives me to
a lot of problems so I decided to move to Linux + Apache + Postgres database – MyApp specific models will be handled by postgres database, but I still need to have access to for example MSSQL UserProfile table. Is there any way to do that? No success till
now :-(
Regards
Szubi
Displaying profile?
Great info. But was wondering how to create a url to display the users profile along with a way for a user to add their own profile info with a form. Once a form is created from the UserProfile model, what kind of view would be required and accompanying
url for that (would the id be user_id or profile_id)?
I'm trying to incorporate profiles from scratch as django-profiles is quite confusing and I'm kind of stuck at the point where profiles are automatically created when a uuser registers, but I want to not only display these, but also have a user able to input
the detailed profile info on their own through a form.
Any help greatly appreciated as I've been at this for hours.
Displaying profile
in urls.py:
(r'^settings/$', user_settings), (r'^settings_changed/$', direct_to_template, {'template':'form_changed.html', 'extra_context':{'message':'Settings has been changed','next':'/settings/'}}),
Somewhere in views.py:
@login_required @csrf_protect def user_settings(request): c = {} c.update(csrf(request)) user = request.user profile = user.profile if request.method == 'POST': # If the form has been submitted... form = UserprofileForm(request.POST,instance=profile) # A form bound to the POST data if form.is_valid(): # All validation rules pass form.save() # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/settings_changed/') # Redirect after POST else: user = request.user profile = user.profile form = UserprofileForm(instance=profile) # An unbound form return render_to_response('settings.html', locals(),context_instance=RequestContext(request))
In models.py:
class UserprofileForm(ModelForm): class Meta: model = UserProfile fields = ('show_thumbnails','interface','style') #put fileds You want user to edit here def clean(self): # add custom validation here cleaned_data = self.cleaned_data interface = cleaned_data.get("interface") st = cleaned_data.get("show_thumbnails") ......... if field_interface_does_not_pass_validation_rules: # We know these are not in self._errors now (see discussion # below). msg = u"Invalid input blah blah!!" self._errors["interface"] = self.error_class([msg]) # These fields are no longer valid. Remove them from the # cleaned data. del cleaned_data["interface"] # Always return the full collection of cleaned data. return cleaned_data
settings.html:
{% extends "base.html" %} {% block title %}Title text{% endblock %} {% block content %} {% if form.errors %} <p class="error">Invalid input</p> {% endif %} <form method="POST" action="/settings/"> {% csrf_token %} <table class="entryTable"> <tbody> {{ form.as_table }} <br><br> <tr><td class="buttons" colspan="2"> <input type="button" class="button" value="Cancel" onclick="location.href='/0/';"/> <input type="submit" class="button" value="Submit"/> </td></tr> </tbody> </table> </form> {% endblock %}
That all ;-)
Szubi
Your URLs File
@Szubi,
Can you please walk me through the URLs file you mention above, I am not sure I understand what each part does.
Thank you,
dp
using the user profile in a reverse lookup…
Hello Alon and THANK YOU!!!
If I found this post last week it would have saved me about 5 days worth of coding and trobleshooting–THANK YOU!
I am new to Django and I am trying to set up a view that uses a reverse lookup in a url. How can I pass the the User's ID number to a url so the user moves from one form on his account (User Information) to another form on his account where he inputs information
directly related to his account?
#views.py def regPage(request): form = RegForm(request.POST) # Save new/edited pick if request.method == 'POST' and form.is_valid(): form.save() return HttpResponseRedirect(reverse('league_page', args=(), kwargs={ 'id' : id })) #return HttpResponseRedirect('/dev/leaguepage/') user_info = UserRegistration.objects.all() context = { 'form':form, 'user_info' :user_info, } return render(request, 'regpage.html', context)
def leaguePage(request, id):
form = LeagueForm(request.POST or
None instance=id and LeagueRegistration.objects.get(id=id))
# Save new/edited pick
if request.method == 'POST'
and form.is_valid(): form.save() return HttpResponseRedirect('/draft/') league_info = LeagueRegistration.objects.all() context = {
'form':form, 'league_info' :league_info,
}
return render(request,
'leaguepage.html', context)
#urls.py urlpatterns = patterns('', #url(r'^leaguepage/$','acme.dc_django.views.leaguePage'), url(r'^user/(?P<id>d+)/$','acme.dc_django.views.leaguePage', name="league_page"), url(r'^$', 'acme.dc_django.views.regPage'), )
Please not the above code doesn't work. This is the code I have been troubleshooting.
Thank you,
dp
版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则按侵权处理.
Hi Alon, thanks for the
Hi Alon, thanks for the interesting and clear post!
I'm currently trying to write a django application that should be based on more than one user profile.. How would your solution coexist with an abstract base-profile? Subclasses could be handled (and attached) on creation with signals or with the (very nice!)
User.profile function, but what about the base one?
Thank you very much,
cico