Opened 7 years ago

Closed 7 years ago

#18352 closed New feature (wontfix)

You can't use AnonymousUser in the database API

Reported by: teolicy Owned by: nobody
Component: contrib.auth Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


There's an ancient ticket (#3413) with the same title, where the person opening the ticket probably failed to realize that you can't use AnonymousUser with the ORM and didn't duly check is_authenticated() before using request.user (or whatever).

I do understand the difference between User and AnonymousUser, and understand the latter can't be used with the ORM, but I think this is poor behaviour which may need correction (though breaking backwards compatibility could be a very good reason not to fix this). I think it's tedious and error prone to check for is_authenticated() all the time, and I had more than one bug where I was bit by request.user not having get_full_name() or .pk or plainly not being searchable as SomeModel.objects.filter(owner=request.user).exists() or so.

I think the best solution would be for AnonymousUser to be 100% compatible with the ORM, and I think the sanest way to get there would be to make it possible to create a User object with reasonable values. Backwards compatibility could be achieved with a setting like AUTH_NEW_STYLE_ANONYMOUS=True, syncdb() could create the record in the database.

I'd love to hear your comments, I'm thinking about implementing this as a (very small) external project if this will be rejected, so in addition to knowing whether this is a good idea for django, I'd appreciate your thoughts about whether this is a good idea at all.

Change History (2)

comment:1 Changed 7 years ago by teolicy

Excuse me if I'm rambling, a couple more thoughts:

  1. Storing the new AnonymousUser in the database will of course have its share of issues, like making it potentially mutable (yikes!) and needing adjustments to is_authenticated() and so. I think all sane usecases can be solved by overriding .save() and .delete(), and bulk updates of the User table are probably very rare and done very carefully.
  2. Perhaps the right setting is AUTH_NEW_STYLE_ANONYMOUS_PK=0 (or similar). That way, you can instantiate AnonymousUser for request.user without hitting the database, by doing something like User(pk=AUTH_NEW_STYLE_ANONYMOUS_PK, first_name=...).
  3. The reason I'm leaning towards making AnonymousUser a real database object (a null object, if you will), is that I fear it's the only sane way to make it 100.0% compatible with the ORM without adding ugly special cases all over the code (hint: currently, we lay the onus of all these special cases on the user, which might not be as careful as framework authors must be). However, I think the AnonymousUser compatibility situation can and should be improved even if my idea of using an actual AnonymousUser record in the database is not the right way to go about doing this.

comment:2 Changed 7 years ago by Aymeric Augustin

Resolution: wontfix
Status: newclosed

I understand your reasons for proposing this, but I'm very reluctant to introduce in Django the solution you're suggestion. It mixes very different things and it's likely to break in all sorts of funny ways. Also I don't like the idea of introducing a setting for this.

To sum up I acknowledge the problem but I don't believe this is an acceptable solution.

Could you bring this up on the django-developers mailing list? This is the best way to see if a new feature has support. Thanks!

PS: this should be doable with a custom authentication backend and/or middleware.

Last edited 7 years ago by Aymeric Augustin (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top