Best approach to handling different types of Users

20 views
Skip to first unread message

Cameron

unread,
Aug 18, 2011, 7:56:14 AM8/18/11
to Django users
Hi, I'm wondering if anyone can help shed some light on the best
approach is too creating different Users. I'm trying to make a online
shop, that features two types of Users, "Customers" and "Merchants".
The power of each Users vary greatly, Customers can buy items from
Merchants and Merchants can (as you would expect) list new products,
edit them. Merchants required additional information compared to
Customers (such as Address, Contact Info, Payment details).

Now hows the best way to handle this? I've read that subclassing the
User class is bad (I'm not entirely sure why though). Most examples
try to extend the User class, with a UserProfile class with a OneToOne
relationship to the User class (like this http://pastebin.com/GQVLrVTx).
Is it better to extend that to a UserProfileMerchant and
UserProfileCustomer, or have a single UserProfile, and have a boolean
field to indicate if the account is a Merchant? (both examples in the
following - http://pastebin.com/F8ZenCa1)

Any advice on the matter would be greatly appreciated!

dfolland

unread,
Aug 18, 2011, 9:17:51 AM8/18/11
to Django users
Try using "Groups" that is part of the Django user authentication.

https://docs.djangoproject.com/en/dev/topics/auth/



On Aug 18, 6:56 am, Cameron <cameronma...@gmail.com> wrote:
> Hi, I'm wondering if anyone can help shed some light on the best
> approach is too creating different Users. I'm trying to make a online
> shop, that features two types of Users, "Customers" and "Merchants".
> The power of each Users vary greatly, Customers can buy items from
> Merchants and Merchants can (as you would expect) list new products,
> edit them. Merchants required additional information compared to
> Customers (such as Address, Contact Info, Payment details).
>
> Now hows the best way to handle this? I've read that subclassing the
> User class is bad (I'm not entirely sure why though). Most examples
> try to extend the User class, with a UserProfile class with a OneToOne
> relationship to the User class (like thishttp://pastebin.com/GQVLrVTx).
> Is it better to extend that to a UserProfileMerchant and
> UserProfileCustomer, or have a single UserProfile, and have a boolean
> field to indicate if the account is a Merchant? (both examples in the
> following -http://pastebin.com/F8ZenCa1)

Andre Terra

unread,
Aug 18, 2011, 9:21:20 AM8/18/11
to django...@googlegroups.com
Do create a UserProfile with an FK to user, but add an FK to Group as well. This way you can take advantage of the existing Permissions application which would allow/deny users access to various parts of your application.

Just make sure your views take those permissions into consideration!


Cheers,
AT


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.


Matt Schinckel

unread,
Aug 18, 2011, 8:57:29 PM8/18/11
to django...@googlegroups.com
Lately, I have been looking at using subclasses of auth.User as a way of segmenting users.

This appears (to me, at this stage, anyway) to have several advantages over using the UserProfile approach.

* You can have extra attributes on the subclass. For instance, one set of users belong to a Company, and I can do this FK relation from the subclass. Similarly, I can have a date_of_birth field that is attached to the user, rather than the UserProfile. From a performance perspective, this doesn't make a lick of difference, as a subclass of a concrete class still has a join anyway.
* You can easily have different user classes appear differently in the admin.
* You can have different relationships between particular User types and other objects. For instance, a Staff user may 'work_at' a Location, but an 'AreaManager' may have a 'manages' relationship to an Area. You can still do this with auth.User, but every user will have every relationship.

The biggest helper for this was to have an authentication backend that automatically selects the subclass, so that you no longer get a User object in request.user, but whatever you want.

A drawback is that you can't easily change the field types: email, which I use for authentication, needs to be unique. You can handle this with validation checking on forms, but that requires you to remember to build this into your forms. The other way is to monkey-patch the User class directly, and manually fix the database to not allow duplicates on the email column.

Andre Terra

unread,
Aug 18, 2011, 10:37:44 PM8/18/11
to django...@googlegroups.com
Until you install some third party app that accesses
User.objects.all() and then suddenly nothing works as it's supposed
to.

You can access the User object from its related UserProfile instance
and do everything you say from there instead of breaking the
convention. Nobody's stopping you from writing an abstract
BaseUserProfile model with an FK to User and custom UserProfile
subclasses. I just don't see any advantages in going down that path.

Because how will you access every user if you ever need to? What if
someone gets promoted? How will you separate view from model logic?
Are you going to rewrite forms for every user class? That's probably
going to be hard to maintain.


FWIW, profiles are the canonical solution. They are also the only
elegant solution, at least until the app loading branch lands on
trunk, which should then allow you to register a different class as
User. But that won't happen any time soon..


Cheers,
AT

> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.

> To view this discussion on the web visit
> https://groups.google.com/d/msg/django-users/-/Y6qCTdPzU9sJ.


> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.
>
>

--
Sent from my mobile device

Matt Schinckel

unread,
Aug 19, 2011, 4:12:36 AM8/19/11
to django...@googlegroups.com

On Friday, August 19, 2011 12:07:44 PM UTC+9:30, Andre Terra (airstrike) wrote:
Until you install some third party app that accesses
User.objects.all() and then suddenly nothing works as it's supposed
to.

Why wouldn't it? The User subclasses will still appear in the User.objects.all() queryset. 

You can access the User object from its related UserProfile instance
and do everything you say from there instead of breaking the
convention. Nobody's stopping you from writing an abstract
BaseUserProfile model with an FK to User and custom UserProfile
subclasses. I just don't see any advantages in going down that path.

 As I said, 'at this stage', it all seems to be working out okay. I have plenty of 3rd party apps, and even some of my own, that access User, and they still work with sub-classes.

Because how will you access every user if you ever need to? What if
someone gets promoted? How will you separate view from model logic?
Are you going to rewrite forms for every user class? That's probably
going to be hard to maintain.

 You can still access User.objects.all(). I even have a way to access the sub-classes (downcasting) when fetching all users.

FWIW, profiles are the canonical solution. They are also the only
elegant solution, at least until the app loading branch lands on
trunk, which should then allow you to register a different class as
User. But that won't happen any time soon..

See, I don't see them as an elegant solution. Having to do:

    user.get_profile().date_of_birth 

instead of:

    user.date_of_birth

irks me every time I write the code. UserProfile has always felt to me that it was a patchy way of extending User.

Matt.

Andre Terra

unread,
Aug 19, 2011, 9:27:15 AM8/19/11
to django...@googlegroups.com
Alright, do what you will. Whatever floats your boat..

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/-B-vk5gzPqcJ.

DrBloodmoney

unread,
Aug 19, 2011, 2:46:00 PM8/19/11
to django...@googlegroups.com

Not being able to define your own User model is easily my least
favorite thing about django. User.get_profile() is an antipattern.

I hope we get the ability to define our own User model makes it into
contrib.auth at some point (lazy loaded)

Malcolm Box

unread,
Aug 20, 2011, 7:03:41 AM8/20/11
to django...@googlegroups.com
On 19 August 2011 03:37, Andre Terra <andre...@gmail.com> wrote:
Until you install some third party app that accesses
User.objects.all() and then suddenly nothing works as it's supposed
to.


I hear this a lot that "things will break" if you subclass User. However, I haven't seen anyone share a concrete example of *how* things go wrong.

Anyone got a good example to scare the children with?

Malcolm

Cameron

unread,
Aug 20, 2011, 11:56:14 AM8/20/11
to Django users

> I hear this a lot that "things will break" if you subclass User. However, I
> haven't seen anyone share a concrete example of *how* things go wrong.
>
> Anyone got a good example to scare the children with?
>
> Malcolm

Yeh, I've heard this quite a bit as well. An example of a scenario
this really catchs you out would be great.

dfolland

unread,
Aug 21, 2011, 4:53:59 PM8/21/11
to Django users
Like I said use the "Groups" and then like what was suggested
"Permissions". That should handle what your are trying to do and not
introduce any conflicts.

Joshua Russo

unread,
Aug 21, 2011, 5:37:52 PM8/21/11
to django...@googlegroups.com
Things will break in the sense that, if you add another app that accesses the User model they will only see the original implementation. They won't get your subclass. Other than that, other apps that use the User model should "work" just fine.

Unless I'm missing something, and in that case someone can kindly correct me. :o)
Reply all
Reply to author
Forward
0 new messages