django-profiles: The Missing Manual

The User model in Django is intentionally basic, defining only the username, first and last name, password and email address. It’s intended more for authentication than for handling user profiles. To create an extended user model you’ll need to define a custom class with a ForeignKey to User, then tell your project which model defines the Profile class. In your settings, use something like:

AUTH_PROFILE_MODULE = 'accounts.UserProfile'

To make it easier to let users create and edit their own Profile data, James Bennett (aka ubernostrum), who is the author of Practical Django Projects and the excellent b-list blog, created the reusable app django-profiles. It’s a companion to django-registration, which provides pluggable functionality to let users register and validate their own accounts on Django-based sites.

Both apps are excellent, and come with very careful documentation. But here’s the rub: Bennett’s documentation style comes from the mind of an engineer, rather than an average user who just needs to get things done quickly. For people who write Django code every day and are intimately familiar with the official Django docs, they’re probably sufficient. For those of us who don’t have the luxury of being full-time programmers, who don’t live and breathe Django, they’re frustrating. Sample templates are not included, and no clues are given as to what should go in the templates you create. Likewise, the ability to customize the default behavior of the apps is only hinted at, not spelled out. Users coming from a CMS world where you install and configure a plugin and get instant functionality for your site quickly become frustrated.

From IRC logs, it appears that Bennett believes banging your head against a wall is a great way to learn. To an extent, that’s true. I know there’s no better way to learn a new tool than having to solve real-world problems with it. But at the same time, learning doesn’t only take place in the Django docs – it happens on mailing lists, in code samples on djangosnippets.org (which, by the way, is another of Bennett’s projects), and, yes, in documentation for add-on apps like django-profiles.

Let’s take an example: A developer wants to let users edit their own profiles. They get their Profile model registered, install django-profiles, and create a template at profiles/edit_profile.html. What goes in that template? Not much is needed, but the django-profiles docs don’t give you a clue (nor do they give you a clue where to find the answer in the Django docs). You’ll need something like this:

{% extends "base.html" %}
{% block title %}Edit Profile{% endblock %}

{% block content %}
<h1>Edit contact info for {{ user }}</h1>
<form action="" method="POST">{{ form }} <input id="submit" type="submit" name="submit" value="Update" /></form>

{% endblock content %}

Now access /profiles/edit/ and you’ll see all fields on your profile model represented with appropriate field types. So far so good. Now you probably want to customize two things, right off the bat. You may have fields on the profile that only administrators should be able to edit, and you want to hide those fields. And you may want to modify the success_url, to control where the user is sent after a successful form submission. The docs for django-profiles say that the provided edit_profile view takes optional form_class and success_url arguments. But how can you pass in arguments? You’re simply linking to the predefined URL /profiles/edit/ – there is no code of your own from which you can pass in arguments.

This is where things became inscrutable to me. I was at an impasse, with no clue or hint as to what to do next. If the django-profiles docs had included a link to the section of the Django docs that contained the answer (or some kind of directional indicator) I could have done the research and gotten things moving. Fortunately, a friend and fellow Django developer had been down this road before and had the solution. Here’s how the pieces connect:

First, you need to create a custom ModelForm based on your Profile model. If you don’t already have a forms.py in your app, create one, then add something like:

from django.db import models
from django.forms import ModelForm
from ourcrestmont.itaco.models import *

class ProfileForm(ModelForm):
  class Meta:
      model = Foo
      exclude = ('field1','field2','field3',)

The idea is to pass your custom ModelForm to django-profiles with the name form_class, thereby overriding the default object of the same name. django-profiles will then operate against your custom ProfileForm rather than from a default representation of your Profile model. Once I understood this, the light went on and things started to snap into place.

Still, how can you pass this custom form_class to django-profiles, when there’s no view code in your own app to handle this? That’s where trick #2 comes in: The seldom-used ability to pass dictionaries of custom values in from your urlconf. So wiring things up now becomes a pretty straightforward task. In urls.py, import your custom form and pass it through to the django-profiles view, right before the reference to the django-profiles urlconf. Because Django will use the first matching URL it finds, you want to do this before the django-profiles-provided URL is found so you can override it.

from projname.appname.forms import ProfileForm
    ('^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm,}),
    (r'^profiles/', include('profiles.urls')),</pre>
You can pass in your custom success_url value in the same way:
<pre lang="python">from projname.appname.forms import ProfileForm
    ('^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm,'success_url':'/my/custom/url',}),
    (r'^profiles/', include('profiles.urls')),

Now access /profiles/edit/ again and you’ll find that the view is using your custom form definition, rather a default one derived from the profile model. Pretty easy once you see how the pieces fit together.

If you need even more control than that, there’s another alternative to passing a dict in through the urlconf – write your own view with the name edit_profile, overriding aspects of the provided view of the same name:

from profiles import views as profile_views
from myprofiles.forms import ProfileForm

def edit_profile(request):
  return profile_views.edit_profile(request, form_class=ProfileForm)

(I haven’t tried this method).

profile_detail and profile_list

django-profiles enables other templates as well. As documented, the “details” template lets you retrieve all data associated with a single profile by sending an object named “profile” to the template profile/profile_detail.html, e.g.:

<strong>Address 2:</strong>{{ profile.address2 }}

<strong>City:</strong>
{{ profile.city }}

It’s not quite so clear how to get a list of all profiles in the system. The docs say:

profiles/profile_list.html will display a list of user profiles, using the list_detail.object_list generic view

You’ll access the list view at /profiles/, with template code along the lines of:

{% for p in object_list  %}
<a href="{% url profiles_profile_detail p.user %}">{{ p }}</a>&gt;
{% endfor %}

(in other words you can ignore the “list_detail.” portion of the object name referenced in the docs).

Let Users Edit Their Own Email Addresses

A common task when editing profile data would be to change one’s email address. But since the email address is included in the User model and not in the Profile model, it doesn’t show up in the {{form}} object.

The solution is to add an email field to the Form object (not the Profile model – that would not be DRY), then put a custom save method on the form that retrieves the corresponding User and updates its email field. Here’s a complete ProfileForm that does all of the above. With a little tweaking, this will also let users edit their first and last names.

class ProfileForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        try:
            self.fields['email'].initial = self.instance.user.email
            # self.fields['first_name'].initial = self.instance.user.first_name
            # self.fields['last_name'].initial = self.instance.user.last_name
        except User.DoesNotExist:
            pass

    email = forms.EmailField(label="Primary email",help_text='')

    class Meta:
      model = Profile
      exclude = ('user',)        

    def save(self, *args, **kwargs):
        """
        Update the primary email address on the related User object as well.
        """
        u = self.instance.user
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(ProfileForm, self).save(*args,**kwargs)
        return profile

With a few well-placed links and code samples, the django-profiles docs could be a great learning opportunity for this kind of Lego-like site construction. Until then, I’ll update this post with any other tips users provide on django-profiles implementation.

Despite my gripes about the docs, many thanks to Bennett for all of his excellent free code, writing, and other contributions to the Django community. And a ton of thanks to mandric for the golden ticket on how to wire up the pieces.

No missing profiles!

Update: Astute readers (OK, Enis in the comments :) will have noticed that the profile editing form works fine for users with existing profiles, but breaks for new users who don’t yet have profiles. The trick is to make sure there are no users in your system who don’t have profiles – having a profile must be a baseline requirement of your system.

You’ll need to create a signal that automatically generates a blank profile record whenever a User instance is created. You’ll also need to back-fill your database to make sure all old users have profiles. Here’s how I solved those problems.

# in models.py:

from django.db.models import signals
from bucket.signals import create_profile

# When model instance is saved, trigger creation of corresponding profile
signals.post_save.connect(create_profile, sender=User)</pre>
... and then the actual signal to be fired:
<pre lang="python"># in signals.py:

def create_profile(sender, instance, signal, created, **kwargs):
    """When user is created also create a matching profile."""

    from bucket.models import Profile

    if created:
        Profile(user = instance).save()
        # Do additional stuff here if needed, e.g.
        # create other required related records

Now try creating a new User object, either via the admin or by registering, and check to make sure a corresponding blank Profile record has been created. If that’s working, all you need to do is back-fill your system so everyone has a profile. Something like this should do the trick:

$ python manage.py shell

from django.contrib.auth.models import User
from bucket.models import Profile

users = User.objects.all()
for u in users:
     try:
          p = u.get_profile()
     except p.DoesNotExist:
          Profile(user = u).save()

There is one potential gotcha if you’re starting out with a fresh system, or migrating to another database, etc. – if syncdb asks if you want to create a superuser and you say yes, that user will end up without a profile, because your fancy new signal can’t be invoked. You may then end up with some odd SQL errors when trying to syncdb later on. Solution: Skip that step and create your superuser later on (with manage.py createsuperuser).

That should do it!

Looking for a set of starter templates for django_profiles? Here is the set used on bucketlist.org (I am the developer for that site). You will of course need to hack and modify them to suit your needs.

115 thoughts on “django-profiles: The Missing Manual

  1. adrianliem

    could you please also give me some clue about the contents of the profile_detail.html & profile_list.html ? thanks :)

  2. shacker Post author

    Hey adrianliem – I’ve updated the post with info on retrieving object data for profile_detail and profile_list in your templates.

  3. adrianliem

    hey thanks for the update :)
    about the email problem you questioned, if i may suggest you, you can try to ask the question in stackoverflow.com — usually i ask questions about django in there, and the people there are pretty helpful :)
    have a great day!

  4. Colin

    Great post, thanks. If you figure out the email business I would be really appreciative. Also, what do you do if you want more user info on the profile detail page?

    For example, if I have users adding notes to a site, and I want their profile page to list all the notes they’ve added. Is that what the “context” business is all about?

    Thanks again.

  5. shacker Post author

    Colin – I havent’ solved the email editing problem yet, but I did post the question at StackOverflow and some hints on how to approach the problem are there.

    As for extra notes, those really shouldn’t be part of the profile – you should create a separate Notes model with a ForeignKey to the user’s profile, then use the __set notation to retrieve them. That way a user can have as many notes as you like attached to their profile without having to do hack-y things like putting note1, note2, note3 on the profile model.

  6. Colin

    Wow. Fast response time!

    Thanks for the tips. I knew about the One To Many business and the “_set” thing, my problem is that I’m up to late. Here on the East Coast it’s past 1, and I apparently forgot that all I needed to do to reference notes was do a user.note_set.all to get the notes for a user…sorry to clog the instruments!

    Also, I took a gander at your post on StackOverflow and I think I understand the idea of having separate pages for such things.

    Anyway, I’m done for the night. Happy hacking, and thanks again.

  7. Colin

    One last thing. Interesting to see on your twitter profile that you work at the Berkley J-school. I’m a reporter for a small weekly out here in Maine and am using django to help morph my job description into a reporter/web developer for the company… Amazing stuff going on in the internet/journalism world these days, good luck!

  8. shacker Post author

    Love to hear examples of Django being used in journalism – especially by non-hardcore programmers. Let us know when you’ve got something up for the world to see – would love to take a look.

  9. Jonas Rullo

    Thanks so much, I used your post to get most of my info to show up. However on the list view, your example only gave me a link “object list”. I changed {{ p }} to {{ p.user }} to get my user name to appear on the list page. The link does click through to the detail page, but the url in the link is http://domain/full/server/path/to/project/profiles/p.user
    Shouldn’t the url path just be domain/detail/p.user
    or something similar? The resulting detail page has a link with the correct profile, so it clicks through to the edit page. I’m concerned about the url path generated on the profiles list page. It seems like that path should not even work.

    How would I get the normal path generated in the profiles list page?

  10. shacker Post author

    I changed {{ p }} to {{ p.user }} to get my user name to appear on the list page.

    That sounds like you might not have an appropriate unicode method set on your profile model. {{p}} should render exactly as specified in that method.

    Links to profile pages are defined in the urls.py belonging to django-profiles, so if you want to change them you can edit them there.

  11. Reinhardt

    How to set AUTH_PROFILE_MODULE? Should I create a models.py in the root directory of the project, create a model class (eg. UserProfile) and then set the value of AUTH_PROFILE_MODULE to myproject.UserProfile, or to myproject.models.UserProfile?

    Or should I create an app for only have the models.py in it (startapp UserProfileModel)??? But then I have two applications installed for one purpose.

    What should I do best? That’s very complicated!

  12. Colin

    Reinhardt: If I may.

    Django docs emphasize the importance of only using the appname.ModelName for the AUTH_PROFILE_MODULE.

    As for whether to create a separate app, don’t. You’ll notice that django-profile does not include a model.py file. Create one and then add a model for your UserProfile with whatever you’d like to add to the User model (url, address, phone number, etc…).

    That becomes your AUTH_PROFILE_MODULE setting:

    AUTH_PROFILE_MODULE=profiles.UserProfile

    Works like a charm.

  13. Jonas Rullo

    OK, so I added:
    def __unicode__(self):
    return self.user.first_name
    to my UserProfile model and the first name automatically appears with {{ p }}.
    Is that just a semantic, or am I saving myself something?

  14. shacker Post author

    Jonas – The point of the unicode method is to provide a default string by which that model is represented anywhere where you don’t specify it otherwise. So if p is your profile and you just call p, you’re now going to get just the first name on this page and anywhere else in your system where you refer to a profile (including in the admin). If you wanted the full name to appear instead you might use:

    return "%s %s" % (self.user.first_name, self.user.last_name)

  15. Reinhardt

    Colin – I installed django-profiles and it is not in my project directory, but in c:\python\lib\site-packages\profiles
    Should I put the models.py in the directory mentioned above, or somewhere in my projects dir?

  16. Jeff

    Can you explain the reason why this works

    (‘^profiles/edit’, ‘profiles.views.edit_profile’, {‘form_class’: ProfileForm,}),
    (r’^profiles/’, include(‘profiles.urls’)),

    Why does listing the profiles/edit first actually get process last?

    I tried it the other way and it defaults to the profiles app. Why does listing it first have it processed last?

    It works, I’m just confused.

    Jeff

  17. shacker Post author

    Jeff – profiles/edit is defined in profiles.urls, so it’s essentially being defined twice – once in the Profiles app itself and once by you. When Django is processing URLs, it always grabs the FIRST match it finds in the list of all possible URLs. So since you want to override the view provided by the Profiles app you need to make sure Django intercepts your URL definition BEFORE the one provided by the Profiles app.

  18. Jeff

    Shacker,

    The is this correct?

    In urls.py, import your custom form and pass it through to the django-profiles view, right after the reference to the django-profiles urlconf (you want to do this after, not before, so the last matching URL for /profiles/edit/ is the one you define, not the one django-profiles defines:

    BTW – liked your article about Six Flags. I just took my family to Sea World and experienced some of you pain, although I guess the east coast is a little more affordable – we only paid $10 to park :)

  19. ste

    Hi, with this package is possible to manage different profiles for different kind of users? How ca I do?

  20. shacker Post author

    Ste – Yes, but that’s a very different problem from the one this blog post is talking about. Basically you’ll want to create multiple profile models, all with non-overlapping sets of attributes. What you’ll lose is the ability to define an canonical profile model in your Django project. But you’ll need to ask more specific questions if you have more – try the django-users mailing list.

  21. Michał

    Great article. It helped me a lot though i must say that docs for both django-profiles and django-registration are as not as bad. I had to get used to way in whiach they are written.

  22. Jay

    Hi Scot, this was helpful! Thanks for writing up this missing manual :)

    Btw, with that snippet on editing email address – I looked through all the comments above and on the StackOverflow link, but I didn’t see the reasoning behind it. I see that with the __init__, upon instantiation of ProfileForm, you’re trying to get the current email addr .. somehow by calling ProfileForm’s superclass (which is ModelForm, right?) But that’s where I don’t quite connect the dots and see how ModelForm can access the User object’s values.

    Can you walk us through that? Thanks in advance.

  23. Jay

    Ah nevermind – I figured it out with pdb.

    calling super() is because you’re overriding __init__ and save(). The way you’re obtaining the email address is via self.instance.user.email where self.instance is the instance (of the custom model), self.instance.user is the built-in user object, thus self.instance.user.email is the email field from the build in user object

  24. Steff

    Hi, I got a big Problem with this code:
    Just in init(), as in save() the instance is not known and raises a DoesNotExist exception.
    I thought it worked one time, but i don’t know when and why :/

    Calling via:
    (r’^profiles/create’, ‘profiles.views.create_profile’, {‘form_class’: ProfileForm}),

    class ProfileForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
    super(ProfileForm, self).__init__(*args, **kwargs)
    try:
    self.fields['email'].initial = self.instance.user.email
    self.fields['first_name'].initial = self.instance.user.first_name
    self.fields['last_name'].initial = self.instance.user.last_name
    except User.DoesNotExist:
    pass

    Exception already raised here… But the User DOES exist.

    Debugger says:
    self.instance: Unable to get repr for

    One thing I’ve recently done is changing the Customer-class (Customer=Profile). I’ve deleted two fields. I deleted the auth_user and the customer-tables and ran sync-db, nothing works..

    Any idea?

  25. shacker Post author

    Steff, since this is the “create” stage, the user object does not yet exist. It looks like your code is trying to deal with an existing user, which is a different process. In fact, your question really pertains to django-registration, not django-profiles. If you want custom fields during the user+profile creation stage, you need a different approach.

    Maybe this response at StackOverflow can help to re-orient you?

  26. Steff

    Well, seems like I wasn’t seeing the wood for the trees a while ago after hours of coding.
    The problem is: The User may exist, but the Profile (Customer) doesn’t. I didn’t even think of this problem, because it already didn’t “find” the User, but in fact it can’t find the User because it is a Foreign Key in the Customer-Object which doesn’t exist at the moment. Right?
    I’ve solved with catching the signal after creating a user.

  27. shacker Post author

    Hmm, you really shouldn’t need any custom signals – django-registration and django-profiles may have their own internal signals but they don’t require you to write any. But in any case, glad you got it working.

  28. Pingback: Aptana Studio and “Undefined variable from import: DoesNotExist” | Mitch Fournier

  29. Marco

    hi! thanks for code sharing!

    Two questions:
    A) if i want the email field prefilled with (old) email?
    ( maybe a instance option in
    email = forms.EmailField(label="Primary email",help_text='')??)

    B) The user field is filtered( i cant’ see other users). when i create the profile the user field appears as a select form with default value null (——–) and 2nd value user “MyUser”. What should I do to have default (unique) value “MyUser”)?

    Marco

  30. shacker Post author

    Marco –

    A) To get a field pre-filled, you want to use the Initial option.

    B) I’m not clear whether you’re referring to the Django Admin or a custom view. If it’s a custom view, why is the user field showing at all? A user can only ever edit their own profile – there shouldn’t be a User picklist there at all.

  31. Darren

    shacker thank you for this post. I found it really useful and I was one of the many who didn’t have a clue even after reading those very vague provided docs. This is going to help many other I’m sure of it.

  32. Enis

    This works great for editing an existing profile, but a discrepancy exists when a new user registers. Then, the ‘create’ form is different from the ‘edit’ one and contains only the fields in the UserProfile but not the User model. Simply changing the urls.py to redirect /profiles/create to the same form/view used for editing a profile fails because the given entry does not yet exist in the UserProfile table. Any suggestion as to how to create user’s profile in the the existing view or a better method for achieving consistency would be greatly appreciated.

  33. shacker Post author

    Enis – You need to use a similar technique to the one above. In my case, I created a form class EnhancedRegistrationForm which subclasses django-registration’s RegistrationForm, and capture its url before the other registration URLs. In that URL definition, pass in the form_class for your custom form. That form can then do whatever it needs to do.

  34. Enis

    Thanks for the prompt response. However, it turns out I should not have used the word ‘register’ because what I was actually referring to was the initial profile creation process, which happens after a user is already registered vs. the initial user registration. With your example, if a user goes to /accounts/create/ (before they ever created a profile but are registered on the website), they get simply the extra user profile fields defined in the UserProfile model. On the other hand, if a user goes to /accounts/edit/ (after their profile has been created), they see the email (first name, last name) field(s) as well. I am trying to show all of the fields in either scenario and am absolutely not getting anywhere. Redirecting the ‘create’ url to the subclassed profile form (like you show for the ‘edit’ url), the fields are displayed but, at the time of calling the subclassed save method, the foreign key reference to the ‘user’ does not yet exist in the database so line 22 in your UserProfileForm fails (also ref. line 103 in views.py in django-profiles app). Is there way to get a reference to the ‘request’ object in the subclassed save method? Or something of that nature?
    I guess the only other option is what you said in your response: create a UserProfile object at the time of user registration and allow only editing from then on (but this doesn’t work nicely with already registered users, if the profile option is being added to the site).
    Again, I would be very thankful for any suggestions.

  35. shacker Post author

    Ah, I’m with you now. Yes, good point. In fact, this piece of the puzzle is important enough that I’ve just added a new section to this post called “No missing profiles!” See above for how I solve this problem on bucketlist.org.

  36. Enis

    Your solution with the signals works great! In the end, only 5-6 lines of code and seems so simple but until you know how to do it, seems impossible… Thank you!

  37. shacker Post author

    Happy to help Enis. I totally get your pain. Just 5-6 lines of code… but *which* 5-6 lines? I think Django needs a “Recipes” book from O’Reilly to cover situations like this.

  38. Jimmy Gitonga

    Hi Shacker,

    I am back after the Mac OS X Django install. ;-).

    I have a problem and I can’t figure it out. I have a django-registration paired with django-profiles.

    My django-registration is not creating a profile though the signal to do so is being sent. What I get as a blank Profile. I have django 1.2.3, django-registration 0.8.

    Here is my code:
    models.py

    ...
    from django.contrib.auth.models import User
    from django.db.models import signals
    from basic.members.signals import create_profile
    ...

    class Profile(models.Model):
    """member model."""
    GENDER_CHOICES = (
    (1, 'Male'),
    (2, 'Female'),
    )
    user = models.ForeignKey(User, unique=True)
    first_name = models.CharField(_('first name'), max_length=100)
    middle_name = models.CharField(_('middle name'), blank=True, max_length=100)
    last_name = models.CharField(_('last name'), max_length=100)
    picture = models.ImageField(_('Picture/Avatar'), upload_to='profile_photo', blank=True)
    slug = models.SlugField(_('slug'), unique=True)
    gender = models.PositiveSmallIntegerField(_('gender'), choices=GENDER_CHOICES, blank=True, null=True)
    birth_date = models.DateField(_('birth date'), blank=True, null=True)
    ...

    forms.py

    ...
    from django.forms import ModelForm
    from basic.members.models import Profile
    from registration.forms import RegistrationForm, RegistrationFormTermsOfService, RegistrationFormUniqueEmail
    from registration.models import RegistrationProfile

    attrs_dict = { 'class': 'required' }
    class ProfileForm(RegistrationFormUniqueEmail, RegistrationFormTermsOfService):
    GENDER_CHOICES = (
    (0, 'Select Gender'),
    (1, 'Male'),
    (2, 'Female'),
    )
    first_name = forms.CharField(widget=forms.TextInput())
    last_name = forms.CharField(widget=forms.TextInput())
    picture = forms.ImageField(required=False)
    gender = forms.IntegerField(widget=forms.Select(choices=GENDER_CHOICES))
    birth_date = forms.DateField(widget=SelectDateWidget(years=range(1911,1999)))

    def save(self, user):
    try:
    data = user.get_profile()
    except:
    data = Profile(user=user)
    data.first_name = self.cleaned_data["first_name"]
    data.first_name = self.cleaned_data["last_name"]
    data.gender = self.cleaned_data["gender"]
    data.birth_date = self.cleaned_data["birth_date"]
    data.save()
    ...

    signals.py

    ...
    from django.db import models
    from django.db.models.signals import post_save
    from django.contrib.auth.models import User

    def create_profile(sender, **kw):

    from basic.members.models import Profile

    user = kw["instance"]
    if kw["created"]:
    profile = Profile(user=user)
    profile.save()

    post_save.connect(create_profile, sender=User)
    ...

    urls.py

    ...
    from registration.views import activate
    from registration.views import register
    import registration.backends.default.urls as regUrls
    from registration.backends.default import DefaultBackend
    from basic.members.forms import ProfileForm

    urlpatterns = patterns('',

    url(r'^register/$', register, {'backend': registration.backends.default.DefaultBackend','form_class': ProfileForm }, name='registration_register'),
    ...

  39. shacker Post author

    Jimmy – It looks like you’re duplicating data (first, last name) in the Profile that’s already in User. You don’t need to do that. All you need is a blank profile with a FK to the User. Here’s the signal I use to create a Profile when a User object is created:

    
    def create_profile(sender, instance, signal, created, **kwargs):
        """When user is created also create a matching profile."""
    
        from bucket.models import Profile
        
        if created:
            Profile(user = instance).save()
    
    

    and it’s triggered by this in models.py:

    signals.post_save.connect(create_profile, sender=User)

    HTH,
    ./s

  40. Jimmy Gitonga

    I made the changes and I still get the same problem.

    So I built a simple project “customprofile” with an app called accounts. In this app is all the templates for django-registration and django-profiles. All the urls are as per the examples:


    urlpatterns = patterns('',

    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
    (r'^accounts/', include('accounts.urls')),
    ('^profiles/edit', 'profiles.views.edit_profile', {'form_class': UserProfileForm,'success_url':'/profiles/',}),
    (r'^profiles/', include('profiles.urls')),
    )

    So here goes:

    #settings.py

    AUTH_PROFILE_MODULE = "accounts.UserProfile"
    ...

    INSTALLED_APPS = (
    ...
    'accounts',
    'registration',
    'profiles',

    #models.py

    ...
    from django.contrib.auth.models import User
    from django.db.models.signals import post_save
    from accounts.signals import create_profile

    class UserProfile(models.Model):
    """User with app settings."""
    user = models.ForeignKey(User, unique=True)
    middle_name = models.CharField(_('middle name'), max_length=100)

    class Meta:
    verbose_name = _('Profiles')
    verbose_name_plural = _('Profiles')
    db_table = 'Profiles'

    def __unicode__(self):
    return u'%s' % self.middle_name

    @permalink
    def get_absolute_url(self):
    return ('profiles_detail', None, {'slug': self.slug})

    post_save.connect(create_profile, sender=User)

    #forms.py

    from accounts.models import UserProfile

    attrs_dict = { 'class': 'required' }
    class UserProfileForm(forms.Form):

    middle_name = forms.CharField(widget=forms.TextInput())

    def save(self, user):
    try:
    data = user.get_profile()
    except:
    data = UserProfile(user=user)
    data.middle_name = self.cleaned_data["middle_name"]
    data.save()

    if created:
    UserProfile(user = instance).save()

    #signals.py

    from django.db import models
    from django.db.models.signals import post_save
    from django.contrib.auth.models import User

    def create_profile(sender, instance, signal, created, **kwargs):
    """When user is created also create a matching profile."""

    from accounts.models import UserProfile

    So I have removed the duplicating data issue, (firstname, lastname), put in middle_name as the only custom field to add.

    A number of problems arise:

    1. On registration, the firstname, last name from the User do not appear in the form only the username, email and password(x2). How do we get these name fileds to show? I was duplicating because I had no idea on this one.
    2. On registering, the User gets saved very well, but it seems the UserProfile gets created by the signal but the “middle name” form entry does not get entered into the database.

    So what we get is a UserProfile entry that has a blank under “Middle name” in the django admin. So there is no url link into the UserProfile to edit it. If I register another user, no UserProfile is created.

    This, my friend, is what has me stumped for a 11 days. I use a virtualenv for there is no contamination with my default install of Django.

    What do you think?

  41. LUC@X

    Hi shacker, this article really helped me out with some profile issues…. Thank you very much for sharing !!

    To Jimmy Gitonga:
    You just need to read out, it’s explained, you can use all the fields you want in your Profile model, i understand it would be addecuate to set the first and last name in the Auth model but it will work as expected both ways.

    have you tweaked out sucessfully the ‘ProfileForm’ provided in this article to accept modification of the first name and last name?

  42. shacker Post author

    Francis, sorry – I take it as a given that the developer will know how and where to replace project and app identifiers from my sample code with the relevant project and app names from your own.

  43. anshul

    Hi shacker,

    your solution works perfectly, but i have gotten into a small problem when I edit the profile of a user and try submitting the form it gives me validation error on Email field that field is required.But the email address field already has email address,I have tried editing the email address on same form and saving it then also it shows same error email field required.

    My edit_profile.html is

    {% extends "admin/test.html" %}
    {% load i18n %}

    {% block title %}Edit Profile - {{ block.super }}{% endblock %}

    {{ block.super }}

    {% block maincontent %}

    Edit Profile for {{ user }}

    {% csrf_token %}
    {{ form.full_name.errors }}
    Full name:{{ form.full_name }}
    {{ form.full_address.errors }}
    Billing address:{{ profile.full_address }}
    {{ form.phone.errors }}
    Phone:{{ form.phone }}
    {{ form.email.errors }}
    Email address:

    {% endblock maincontent %}

    Please help me finding solution.
    Thanks

  44. anshul

    Hi shacker mys forms.py is this

    class ProfileForm(ModelForm):

    def __init__(self, *args, **kwargs):
    super(ProfileForm, self).__init__(*args, **kwargs)
    try:
    self.fields['email'].initial = self.instance.user.email
    except User.DoesNotExist:
    pass

    email = forms.EmailField(label="Primary email",help_text='')

    class Meta:
    model = UserProfile
    exclude = ('user',)

    def save(self, *args, **kwargs):
    """
    Update the primary email address on the related User object as well.
    """
    u = self.instance.user
    u.email = self.cleaned_data['email']
    u.save()
    UserProfile = super(ProfileForm, self).save(*args,**kwargs)
    return UserProfile

  45. shacker Post author

    anshul, I have to admit I’m stumped. I’d post your question (with full code) on StackOverflow. Let us know what you figure out!

  46. anshul

    Hey Shacker,

    I figured it out , the problem was with the template “edit_profile.html”. I was using the name=”id_email” instead of name=”email” that why django was not able to update in database because it wants the email-address field name to be “email”.

    Anyways thanks for your support

    TC

  47. airtonix

    shacker,

    you start your post out by slagging off the author of django-registration citing “…he thinks banging your head against the wall is a great way to learn…” and “…they assume you know what to fill in….

    and yet, you go onto write code examples that force new users to “learn by banging their head against the wall”.

    I would suggest that before you try to extol the virtues of your post based on the detriment of others, that you first make sure your code examples and instructions can be used without any modifications.

  48. airtonix

    you may not like what i said in my previous comment, however the vehemence used does not invalidate the inconsistency of your presentation.

    Simply revisiting the contents of this post and ensuring that there can be no assumptions made that would lead to errors.

    in short, the examples here should work verbatim.

    When i followed this post, I actually used pip to look for bucket and the others… only shortly thereafter realising that these were not essential.

    it was unnecessarily confusing since you start the post out with explaining that the reader should define :

    AUTH_PROFILE_MODULE = ‘accounts.UserProfile’

    and yet later on in your code examples you then change how you address your UserProfile model to something else completely different.

    Addressing little points like this will make a great post perfect.

  49. shacker Post author

    airtonix – It would not be possible to make the examples work verbatim because they need to reference YOUR models, not mine. I think that much goes without saying. I mean, when you see:

    from bucket.signals import create_profile

    You know that you don’t have a module called “bucket” on your python path, right?

  50. varun

    Hi Shacker,

    first I justed wanted to say thanks for creating this blog post, because without it i really would not been able to put the profile app to good use

    having said that, i was hoping if you could help with an issue to further add some functionality to user profiles where i am trying to create a way where it can keep track of (most recent) users that have logged in (and registered an account, e.g. user w/ user_id = 2, user_id = 3, etc.) that have viewed a specific (registered) user’s profile page (e.g. user w/ user_id = 1) located at r’^profiles/username

    i think the models.py can simply be something like

    class Visit(models.Model):
    user = models.ForeignKey(User)
    visitor = models.ForeignKey(User, related_name=’visitors’)
    visitor_date = models.DateTimeField(auto_now_add=True) #track most recent visitor by timestamp

    but when it comes to the views and templates, particularly views, its becoming unclear

    would i need to implement anything regarding sessions, such as user session keys, cookies, etc or can it be implemented much simpler than that, thanks

    -v

  51. Jimmy Gitonga

    Hi varun,

    I was in a similar situation and I found out, there is no short cut to learning Python programming. Bite the bullet and in a month or 2, you will be able to write views quickly.

    In fact, in Django 1.3, its even easier than previously. I recommend, the books, ‘Learning Python’ and ‘Programming Python’. That’s what I am going through now.

  52. Scot Hacker

    Varun, I think you’re basically on the right track, but it’s off-topic for this thread. There are a number of moving parts in your plan – just start with that model and start adding bits and pieces, e.g. if a profile page is accessed by a logged in user, then create and save a Visit() record. I suggest spending a lot of time at StackOverflow!

  53. varun

    hey thanks so much for your replys guys,

    yea i tried searching through stackoverflow wasnt able to come up with any answers… ive always had issues with the save() function, especially with examples ppl used to overwrite it using *args, **kwargs, still havent gotten my head around those :(

    it is kind of a specific issue, havent gone through work learning python, guess you can say its not my native language… i guess ill have to do some hw to do….

    -v

  54. david

    shacker,

    i actually stumpled across your article at
    http://birdhouse.org/software/2009/09/listgen/
    but thought it was more pertinent to post here…

    anyways im trying to implement a profile system in django for users belonging to different groups (e.g. members, businesses) where users belonging to different groups (member, business) will have different information displayed so that after a user logs in, the website displays the corresponding menus, profiles, and other information depending on whether the user is a member or a business

    i figured that since you had developed something for a school site comprising of different user types (Students, Parents, Teachers, Staff, and Alumni) having multiple profile types that you might be able to share your thoughts on what you believe to be the best or most flexible way of implementing this. thanks.

  55. Scot Hacker

    David – In our system, there are multiple profile types, all of them subclassing from a single BaseProfile model with common fields. Everyone in the system has one and only one BaseProfile, but can have one or more additional profiles (e.g. a person could be both an alumni and a staff member, so they would have both AlumniProfile and StaffProfiles). We simply obtain and show the right one based on context (which part of the site is being viewed at the time). Users have the ability to edit their profiles of course, and we make sure the right editing form is displayed and processed depending on their memberships.

    HTH.

  56. david

    Scot,

    i guess i should have been more specific with my question.

    so basically im using the django-registration and django-profiles apps. From what you described, im actually trying to implement something very similar (except for maybe the part about showing the profiles where what id like to achieve is showing different views after the user logs in (e.g. using a {% if not user.is_business %} template tag) based on whether the user logged in as a member or business..

    so, i found this on stackoverflow
    http://stackoverflow.com/questions/3100521/django-registration-and-multiple-profiles

    i guess my question really should have been how did you initially setup your registration so that you can determine which users (assuming you are also ONLY using django’s built in user models to setup all your user types) are students, parents, teachers, staff, alumni to begin with

    i also read through http://stackoverflow.com/questions/3189437/how-to-make-multiple-user-types-when-signing-up

    since im really only using two user types, i was wondering if there is a simple way to do something similar to what Tim had asked as a followup from the stackoverflow link above, where for instance, id like to have two links from the main page leading to separate registration forms (main reason for having to separate registration forms is that different user types will require different user profiles fields that id like to have entered at the time of registration) so that after registering from that link the system can determine whether the user is a business or a member.

    so just like tim’s followup, im trying to forgo the step for the user from having to enter a separate field such as using a dropdown menu using a choicefield, where what i was thinking was something like passing in a value to objects in the baseprofile class (ie. is_member = models.BooleanField(default = False) is_business = models.BooleanField(default = False) using a hidden form value or comparing a captured value from url) so that if a user registered through the member link the baseprofile will get a true value for is_member and likewise if a user registered through the link for businesses the baseprofile will get a true value for is_business so that i can that use that value to control which items (e.g. menus, user profiles, etc…) will be displayed in templates …. unless after describing my setup you might know of an easier way to implement this…

  57. shacker Post author

    David, our use case is a bit different. We don’t allow open registration and we control all group memberships from the back-end. We do allow anyone to apply to the school if provided with a “token” (insecure but hard to guess “password”). When they do that they get stored in an Applicants model.

    After our staff use the back-end tools we’ve built to conduct interviews and decide who gets accepted to the school, we batch-convert the selected Applicants into corresponding Users with associated StudentProfile records. That process also fires off email to them welcoming them to the school and letting them know about their logins. In the future, those Students will graduate and a similar process will create additional AlumniProfile records for those same users.

  58. ajt

    I have a field within my Profile for the remote user’s IP address. This field needs to be updated when a user subscribes to my list using the ModelForm method you have outlined above for changing the user’s email address. Do you know how I can access the “request” data within the form? From what I can see, django-profile is not passing the request data to my form.

  59. shacker Post author

    Ajt – in the save() method in the example above, you should be able to just do something like:

    ip = request.META['REMOTE_ADDR']

    No?

  60. DF

    Working on my first Django project and successfully set up django-registration. Now I’m pondering incorporating django-profiles but the many issues seem a bit intimidating. I need just basic profile creation, but the built-in views of django-profiles are attractive. Specifically, the lack of templates are frustrating. There are some great ones listed here, but I’ve searched for a /create_profile template and plain /profile template that showcases the resulting profile to no avail. Are there any available, or at least any info on what goes into these? Also, does django-profiles create the form or does one need to be created? Any insight appreciated.

  61. shacker Post author

    DF, there’s no way around the fact that you’re going to have to heavily modify/hack any set of templates you find out there to suit your needs. That’s in the nature of Django (unlike WordPress or something, templates can’t assume anything about the nature or construction of a site). That said, I’ve attached the set of templates for bucketlist.org to the end of this post – help yourself! Hope you find them useful. In my case, mostly blank profiles are created automatically when users are created, so there is no create_profile template.

    As to the other part of your question, see the ProfileForm section of the original post above.

  62. DF

    Many thanks. I read the documentation and /create_profile was listed as a required template, although I couldn’t discern that those were automatically created from the registration info , so that’s an excellent bit of information that I really appreciate.

  63. DF

    I’m having a bear of a time here. More than 14 hours and I still can’t get django-profiles to work properly

    I finally got it to display a registered users profile and display all registered profiles but I’m having two problems:

    First:

    When I try to access the profiles/edit page, I get this error:

    TemplateSyntaxError at /profiles/edit/
    Caught NoReverseMatch while rendering: Reverse for ‘create_profile’ with arguments

    Second, when I register new users in the admin, it doesn’t create user profiles for them.

    Here’s my setup:

    This is the model in my app:

    class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    email = models.EmailField()
    birth_date = models.DateField(blank=True, null=True)
    city = models.CharField(max_length=25)
    state = models.CharField(max_length=20)
    zip_code = models.CharField(max_length=10)

    def __unicode__(self):
    return ” %s” % (self.user)

    def get_absolute_url(self):
    return (‘profiles_profile_detail’, (), { ‘username’: self.user.username })
    get_absolute_url = models.permalink(get_absolute_url)

    Here’s the form, also located in the app:

    from django import forms
    from stentorian.models import UserProfile

    class ProfileForm(forms.ModelForm):
    class Meta:
    model = UserProfile

    Here’s the beyond basic template for edit_profile:

    {% extends ‘base.html’ %}
    {% block page_title %}Edit Profile{% endblock %}

    {% block headline %}Edit Profile{% endblock %}

    {% block content %}

    {% csrf_token %}
    {{ form.as_p }}

    {% endblock %}

    I hate asking for help, but after so many hours and finding no solutions to these problems, I would really appreciate anyone with expertise ledning their input.

    Many thanks.

  64. DF

    Scot:

    Thanks for your post. Following pieces of it, I was able to get almost everything working that I was pleading (begging) for help with. The profiles now immediately create when a new user is registered through the admin.

    One small issue: The profiles/edit/ was working nicely, but now, it reroutes immediately to the /profiles/create/ template (that was one of the templates in the docs that was instructed to include). How do I resolve this? Should I change the urls?

    Thanks for a terrific resource.

  65. Scot Hacker

    DF, you haven’t given us much information to go on here, but it sounds like this has to do with the order of URL patterns in your urls.py. Remember, whichever URL fragment matches first, wins.

  66. dpbklyn

    Scot,

    Thank you for this. I have been wrestling with profiles for about 18 hours now.

    I am about to dig into your code and before I begin cursing you because of MY shortcomings, I wanted to thank you.

    dpbklyn

  67. dpbklyn

    Scot,

    I am already done-in on step 1. I installed django-profiles and django-registration I added AUTH_PROFILE_MODULE = ‘accounts.UserProfile’ to my settings.py file (of course I used MY APP name). I restarted my apache server and when I try to access /profiles/edit/ I got a 404 error.

    My templates are saved in a /templates/ directory in my project directory (above my app directory). I created and saved the /profiles/ directory in the /templates/ directory. When I got the 404 error, I moved the /profiles/ directory into the templates directory and then to the root of the project–no joy on either.

    Also, I should probably mention my app is installed on a subdirectory….http://website.com/dev

    Thank you for your help,

    dpbklyn

  68. Scot Hacker

    dp – The 404 tells us your urls.py isn’t wired up properly the url request isn’t matching anything (i.e. your problem has nothing to do with templates or app location). What did you put there? Should be something like:

    (r’^profiles/’, include(‘profiles.urls’)),

  69. dpbklyn

    Thank you for yourresponse. You were correct, my urls file was incorrect. When I updated it to include:

    My projectname.profiles.urls:
    (r’^profiles/’, include(‘acme.profiles.urls’)),

    or my app name:
    (r’^profiles/’, include(‘dc_django.profiles.urls’)),

    or just as you suggested:
    (r’^profiles/’, include(‘profiles.urls’)),

    I get an import error:
    ImportError at /profiles/edit
    No module named dc_django.profiles.urls

    Where am I supposed to import the module? I thought I did that in the settings.py file. Do I need to do an “from … import …” at the top of the urls.py file?

    Thank you,

    dp

  70. shacker Post author

    You shouldn’t need an import statement for profiles in your urls.py – if you installed the profiles app in the usual way, it will already be on your path. To test, type:

    python manage.py shell
    import profiles

    That should generate no errors. If it’s generating errors then its not on your path. My usual method for installing 3rd party apps that are in the pypi library is e.g.:

    pip install django_profiles

  71. dpbklyn

    I installed using easy_install. I just tried to re-install both django_profiles and django_registration. I responses similar to:

    ~/webapps/dev/acme/dc_django
    web324:acmefantasy >easy_install django_profiles
    Searching for django-profiles
    Best match: django-profiles 0.2
    Processing django_profiles-0.2-py2.4.egg
    django-profiles 0.2 is already the active version in easy-install.pth

    Using /home/acmefantasy/lib/python2.4/django_profiles-0.2-py2.4.egg
    Processing dependencies for django-profiles
    Finished processing dependencies for django-profiles
    ~/webapps/dev/acme/dc_django

    Thank you,

    d

  72. shacker Post author

    dp, this is devolving into a discussion about why your python paths aren’t working. I’m going to recommend that you take your question to #django on IRC or to StackOverflow or to the django-users mailing list, so as not to derail the topic here. Thanks.

  73. dpbklyn

    yes. I understand. Thank you!

    I still love this thread, Once I get my python paths straightened out, I will be back.

    dp

  74. DF

    Delayed thanks, Scot. Using your solution helped me to be able to have profiles automatically be created once a user is created. Many thanks.

    One question that’s a bit of a stumper. If I want to create a link to a user’s own profile what is the best method? I tried {% url profiles user.username %} but this returns an error. A little stumped here, although it’s probably an obvious solution.

    Thanks for a great resource.

  75. shacker Post author

    Glad you found it useful DF. As for:

    {% url profiles user.username %}

    that depends on what objects are available to your template. Can you render:

    {{user.username}}

    by itself in the template? If not, then it won’t work as an argument either! For you it might be

    {% url profiles request.user.username %}
    or
    {% url profiles profile.user.username %}

    but only you know for sure.

  76. dpbklyn

    OK..I have corrected the issues with my python path. On webfaction there are specific directions for installing python packages. I stupidly didn’t follow them.

    For Other’s reference, they are here: http://docs.webfaction.com/software/python.html#installing-python-packages.

    Now, I know I have the packages installed correctly, I am having trouble getting the page to render when I call it at:

    website.com/profiles/edit.

    I am getting:
    SiteProfileNotAvailable at /profiles/edit/
    Unable to load the profile model, check AUTH_PROFILE_MODULE in your project settings

    I have checked settings.py and the AUTH LINE READS:
    AUTH_PROFILE_MODULE = ‘draft.UserProfile’

    Where draft is my django app name. I tired using my django-project-name.UserProfile but got a similar error message.

    Thank you,

    dp

  77. DF

    Scot:

    Oddly enough, I can access {{ user.username }} within the template, but neither that nor {% url profiles request.user.username %} nor {% url profiles profile.user.username %} works when trying to create a url link.

    The error: Caught NoReverseMatch while rendering: Reverse for ‘profiles’ with arguments ‘(”,)’ and keyword arguments ‘{}’ not found.

    Any insight from anyone would be appreciated.

  78. esse

    All this time and still a very helpful post from you. Thanks for adding this to the common space, I learned a lot a built on it. I will post an extended tutorial to add some more for others.

  79. esse

    To Scot, try using “profiles_profile_detail.” If you are using the default urls.py of django-profiles the reference name for the detail view is “profiles_profile_detail.”

  80. shacker Post author

    DF – esse is right. The reversible URL to view the profile of a particular user is:

    {% url profiles_profile_detail p.user %}

    (or use whatever references your user object in place of p.user) and the url to edit one’s own profile is simply:

    {% url profiles_edit_profile %}

  81. DF

    It worked. Using p.user resulted in the same error, but I used {% url profiles_profile_detail user.username %} and it was exactly what I needed: a workable link!

    Many thanks, esse and Scot. I have struggled for hours with this and something as simple as solving this provides terrific relief along with learning.

    Scot, as a former newspaper reporter who is working hard to learn web development, many thanks for providing a small, specific outlet that can help work out stupid questions like mine. The frustrations from the little things can be overwhelming sometimes but getting beyond, learning from mistakes and staying focused is invaluable.

    esse: one tutorial that would be of great use would be on how to modify django-registration to take in a first and last name along with a username. I’ve found some solutions but they’re not nearly as elegantly written as what Scot has posted here.

    Again, my thanks!

  82. Scot Hacker

    p.user was just an example from my own code – of course you need to use whatever object/variable is in effect on your site there. Glad you got it going.

    Always wonderful to see journalists wading into programming, and Django is such a fantastic and relevant system to do it with. I’ve worked with a lot of journalists over the years (technology training) and have to say I love your persistence on this – that’s the way forward for sure.

  83. DF

    Currently trying to determine the proper way to display an avatar via django-profiles. I’ve added an ImageField to the UserProfile to upload an avatar image. The trick now is not only to display that image in the template, but to size it properly within the context of the template. If there’s a resource that describes this process, it would be welcomed.

  84. Scot Hacker

    DF – I recommend using sorl.thumbnail for that, since users will be uploading their own images and you want them to be resized properly, cached, etc. Google it!

  85. Martin Svendsen

    Thanks for a helpful guide.

    I’m having trouble getting the auto-creation of user profiles working.

    I use the following code in signals.py:

    def create_profile(sender, instance, signal, created, **kwargs):
    “””When user is created also create a matching profile.”””

    from models import UserProfile

    if created:
    print instance
    UserProfile(user = instance).save()

    While the user profiles does get created upon registration, I get the following error:

    IntegrityError at /accounts/register/
    (1062, “Duplicate entry ’32′ for key ‘user_id’”)

  86. shacker Post author

    Hmm, glad that worked, but surprised you needed to do it – I’ve never needed to. I might look deeper at the structure of your app to figure out why that’s being called twice. Might be something as simple as a loop problem.

  87. Martin Svendsen

    Hm, yes, perhaps it’s worth looking into what’s really going on. My site is as minimalistic as it gets right now, there is almost no code written by me that could cause the problem. However, I’m new to Django so I might have missed something, although I have followed the guide as stringent as possible. Perhaps the problem could be, in some obscure way, related to the fact that I’m running the site inside a virtualenv?

  88. shacker Post author

    virtualenv wouldn’t be a problem – that’s definitely the recommended way to go. You might post relevant code on stackoverflow or the google group and see if you can get some input there.

  89. peanutz

    amazing !

    I must agree the hardest part in django is to gather appropriate information around the interwebs . This post along with a bunch of docs and stackoverflow threads made my day, i now understand django much better and had my very first registration/profile system up and running :)

    Thanks !

  90. DF

    Hi Scott. Potential problem that I hope you can aid with. My first app is near completion and I’m currently transitioning to a Postgres database in anticipation of deploying via Heroku. The process was going fairly smoothly until this occurred when I ran python manage.py syncdb.

    django.db.utils.DatabaseError: relation “report_userprofile” does not exist
    LINE 1: INSERT INTO “report_userprofile” (“user_id”, “first_name”, “…

    Apparently, it did not create DB tables for the UserProfile model. I’m now getting this exception when I attempt to run the server:

    Exception Type: DoesNotExist at /accounts/login/
    Exception Value: Site matching query does not exist.

    I was researching what might have gone wrong and came across this post on Google Groups and answer which states that “If you’re using a post_save signal on User you can’t do that because it results in a race condition.

    I am using the signals.post_save.connect(create_profile, sender=User) recommended above. I’m wondering if this may be causing the issue and, obviously, what would be best to resolve it and get these tables into the new database and functioning.

    Any insight greatly appreciated.

  91. Scot Hacker

    DF – The post_save technique has always worked for me, and I haven’t experienced issues with it. But from your description of the problem, it sounds like the table doesn’t even exist. Stupid question, but you have already run syncdb, right?

  92. DF

    Hi Scott:

    Yes. That’s when the error occurred in the shell:

    django.db.utils.DatabaseError: relation “report_userprofile” does not exist
    LINE 1: INSERT INTO “report_userprofile” (“user_id”, “first_name”, “…

    I’m using South but I first ran “sync.db” to create the initial tables., which is when this error occurred. Even when migrating, though, afterward ‘profiles’ no longer appears as a migrated app.

    I was previously using sqlite3 and everything worked. This is what the model inquestion looks like:

    class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True, related_name=”profile”)
    first_name = models.CharField(max_length=25)
    last_name = models.CharField(max_length=35)
    email = models.EmailField()
    birth_date = models.DateField(blank=True, null=True)
    city = models.CharField(max_length=25)
    state = models.CharField(max_length=20)
    zip_code = models.CharField(max_length=10)
    profile_pic = models.ImageField(upload_to=’profilepictures’, blank=True)

    def __unicode__(self):
    return ” %s” % (self.user)

    def get_absolute_url(self):
    return (‘profiles_profile_detail’, (), { ‘username’: self.user.username })
    get_absolute_url = models.permalink(get_absolute_url)
    signals.post_save.connect(create_profile, sender=User)

    And this is the signals.py file that complements it:

    def create_profile(sender, instance, signal, created, **kwargs):
    “””When user is created also create a matching profile.”””

    from stentorian.report.models import UserProfile

    if created:
    UserProfile(user = instance).save()
    # Do additional stuff here if needed, e.g.
    # create other required related recordsuired related records

    Not sure what the problem might be.

  93. DF

    It appears the problem was resulting from creating a superuser before the profile tables synced. It was creating a user without a profile, thus causing the error.

    Declining to create a superuser at first and creating one after the tables were synced solved the problem.

  94. shacker Post author

    Thanks Erik – I’ve updated the download to include that template (I never use it since I use signals to create profiles automatically when User objects are created).

  95. erik

    In your example on custom urls

    e.g.:
    (‘^profiles/edit’, ‘profiles.views.edit_profile’, {‘form_class’: ProfileForm,}),

    you might want to pass in url instances (https://docs.djangoproject.com/en/dev/topics/http/urls/#url) instead and include the name parameter too.

    for example:
    url(r’^profiles/edit/$’, ‘profiles.views.edit_profile’, kwargs={‘form_class’: ProfileForm,},name=’profiles_edit_profile’),

    From what I understand, ‘name’ is needed so that reverses will work in the library.

  96. erik

    If you get a chance, could you explain what pythonic magic is in the lines:

    class Meta:
    model = UserProfile
    exclude = ['user',]

    I understand model is a reference to my UserProfile, but not sure what we are doing putting into a Meta class… or what Meta class is doing here at all (or what exclude is doing). Thanks.

  97. shacker Post author

    When defining a form based on a model, the Meta is used to tell it what model to base itself on. Since you don’t want users to edit their own usernames, we exclude that field.

  98. JX3

    This was definitively helpful. It’s really hard to find good tutorials for Django outside the “official” ones. I don’t know why as Django seems to be a pretty old and well known framework. Whatever the reason; tons of thanks to you. I’m very grateful.

Leave a Reply