views:

1526

answers:

7

I'd like to create a subset of Users that don't have a login... basically as a way to add a photographer field to photos without having a full blown account associated with that person (since in many cases, they'll never actually log in to the site). A caveat is that I'd also like to be able to enable an account for them later.

So, I think the question becomes what's the best way to set up a "People" table that ties to the User table without actually extending the User table with UserProfile.

+4  A: 

A user profile (as returned by django.contrib.auth.models.User.get_profile) doesn't extend the User table - the model you specify as the profile model with the AUTH_PROFILE_MODULE setting is just a model which has a ForeignKey to User. get_profile and the setting are really just a convenience API for accessing an instance of a specific model which has a ForeignKey to a specific User instance.

As such, one option is to create a profile model in which the ForeignKey to User can be null and associate your Photo model with this profile model instead of the User model. This would allow you to create a profile for a non-existent user and attach a registered User to the profile at a later date.

insin
A: 

From the documentation on django auth, if you want to use the User model, it's mandatory to have a username and password, there are no "anonymous accounts". I guess you could create accounts with a default password and then give the opportunity for people to enable a "real" account (by setting a password themselves).

To set up a "People" table that ties to the User table you just have to use a ForeignKey field (that's actually the recommended way of adding additional info to the User model, and not inheritance)

Farinha
A: 

Users that can't login? Just given them a totally random password.

import random
user.set_password( str(random.random()) )

They'll never be able to log on.

S.Lott
A: 

Using a model with a ForeignKey field linking to User might not work as you want because you need anonymous access. I'm not sure if that's going to work, but you might try what happens if you let it have a ForeignKey to AnonymousUser (whose id is always None!) instead.

If you try it, post your results here, I'd be curious.

Hanno Fietz
+2  A: 

Supply your own authentication routine, then you can check (or not check) anything you like. We do this so if they fail on normal username, we can also let them in on email/password (although that's not what I'm showing below).

in settings.py:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'userprofile.my_authenticate.MyLoginBackend', # if they fail the normal test
 )

in userprofile/my_authenticate.py:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User

class MyLoginBackend(ModelBackend):
    """Return User record if username + (some test) is valid.
       Return None if no match.
    """

    def authenticate(self, username=None, password=None, request=None):
        try:
            user = User.objects.get(username=username)
            # plus any other test of User/UserProfile, etc.
            return user # indicates success
        except User.DoesNotExist:
            return None
    # authenticate
# class MyLoginBackend
Peter Rowell
A: 

The django.contrib.auth.models.User exists solely for the purpose of using default authentication backend (database-based). If you write your own backend, you can make some accounts passwordless, while keeping normal accounts with passwords. Django documentation has a chapter on this.

zgoda
A: 

Another upvote for insin's answer: handle this through a UserProfile. James Bennett has a great article about extending django.contrib.auth.models.User. He walks through a couple methods, explains their pros/cons and lands on the UserProfile way as ideal.

saturdayplace