Re: Inheritance question: Multiple roles for users

2013-04-18 Thread M Hill

>
> Model inheritance is not the same as object inheritance. 
>
> If you are doing non abstract inheritance, then there is no difference 
> between a derived model, and a model that has a foreign key to the 
> parent class. In a derived model, the foreign key is a OneToOneField, 
> with null=False, blank=True. In other words, inheritance is exactly 
> the same as composition for non abstract inheritance. The main 
> difference is that if you inherit, the fields that are actually in the 
> parent table magically appear as attributes of your derived object and 
> all your queries involving this table require a join. Magic is bad, 
> extra joins are bad, magic that causes extra joins are double bad. 
>

Tom, Many thanks for the detailed reply. 

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Inheritance question: Multiple roles for users

2013-04-18 Thread Tom Evans
On Thu, Apr 18, 2013 at 5:11 AM, M Hill  wrote:
> I've searched this group for threads related to multitable inheritance.  The
> one most similar to my query so far was titled "multiple children in
> multitable inheritance", from Apr. 2008.  Like the original poster, I'd
> thought of Bar as a possible subclass of Place, which might share the same
> Place parent/base class as a Restaurant.  However, that analogy doesn't
> quite capture what I'm trying to do, so I'll use another.
>
> Say I am managing a martial arts tournament, where Members participate.  I
> would use Member as the base class that would hold all the details common to
> each person, which would include the login name.
>
> Some Members are qualified to be Judges, Timekeepers, Referees, etc.  So
> those people can assume multiple roles at a tournament, but only one such
> role at a time.
>
> The main reason I'd like to subclass Member is so that person-specific and
> role-specific information can be displayed depending on the Member's current
> role.  I saw Malcolm Tredinnick's comment to the effect that the answer to
> using inheritance is usually "no".  However, if I think about using
> Many-to-Many relations to track the Member's available roles, I run into the
> problem that not every Member will be a Judge, so I can't just have a
> "Member.roles -> intermediateTable <- subclass" field.
>
> Furthermore, I need to delegate to another class of Member (TourneyAdmin?)
> the ability to add/manage/remove Members and their roles, and it would be
> very convenient if the admin interface could be used for that purpose.
> However, I can write my own management screens if that turns out to be
> necessary.
>
> I would be very grateful for suggestions on how best to handle this type of
> use case.  I'm sure it's been solved (many times) before, but it seems quite
> difficult to come up with just the right search terms to zero in on the
> right threads without a bunch of false positives.
>
> Thank you.
>

Model inheritance is not the same as object inheritance.

If you are doing non abstract inheritance, then there is no difference
between a derived model, and a model that has a foreign key to the
parent class. In a derived model, the foreign key is a OneToOneField,
with null=False, blank=True. In other words, inheritance is exactly
the same as composition for non abstract inheritance. The main
difference is that if you inherit, the fields that are actually in the
parent table magically appear as attributes of your derived object and
all your queries involving this table require a join. Magic is bad,
extra joins are bad, magic that causes extra joins are double bad.

If you are doing abstract inheritance, then there is no corresponding
base table. In this scenario, to my mind, it is not really
inheritance, the base model only contributes some code and some field
definitions and there is no "is-a" relationship.
Abstract inheritance is very good if you need to define a replaceable
class - it must have these fields, it must have these methods, but you
can add extra fields if you desire.

So, to your hypothetical problem. You have users. Some users are
special users. Special users need some extra attributes store about
them. You need an easy way to determine when a user is a special user.

First, have a User class. I'd use d.c.auth.User, or one derived from
d.c.auth.AbstractBaseUser.

Each special kind of user needs a model too, eg Judge. Each one should
have a OneToOne foreign key to User. You can make this by deriving
each class from User, but I wouldn't bother.

Create a d.c.auth.Group for each type of user. Groups are an object
you can hang Permissions on, and users can be added to as many groups
as necessary. Use the admin to add Permissions to Groups. If you need
more permissions for a specific model, add them to that model's Meta
class.

When you create a Judge instance, add the relevant User to the
relevant Group. When you delete a Judge, remove the User from the
Group. Use signals to hook into this.

Use the permission_required decorator to protect views that should
only be accessible to specific user types. Use a permission you
earlier added to a group.

To determine if someone is a Judge, you look either at their
permissions or their Groups. This could involve extra queries. To work
around this, you can denormalise this information into boolean flags
on the User. Add fields like is_judge to your custom user model, and
populate this data when adding/deleting Judge instances, again using
signals.

In the end, you would end up with view code looking something like this:

@permission_required('myapp.is_judge')
def scoreboard(request):
  judge = request.user.judge
  …


Cheers

Tom

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, 

Inheritance question: Multiple roles for users

2013-04-18 Thread M Hill
I've searched this group for threads related to multitable inheritance.  
The one most similar to my query so far was titled "multiple children in 
multitable inheritance", from Apr. 2008.  Like the original poster, I'd 
thought of Bar as a possible subclass of Place, which might share the same 
Place parent/base class as a Restaurant.  However, that analogy doesn't 
quite capture what I'm trying to do, so I'll use another.

Say I am managing a martial arts tournament, where Members participate.  I 
would use Member as the base class that would hold all the details common 
to each person, which would include the login name.

Some Members are qualified to be Judges, Timekeepers, Referees, etc.  So 
those people can assume multiple roles at a tournament, but only one such 
role at a time.

The main reason I'd like to subclass Member is so that person-specific 
*and*role-specific information can be displayed depending on the Member's 
current role.  I saw Malcolm Tredinnick's comment to the effect that the 
answer to using inheritance is usually "no".  However, if I think about 
using Many-to-Many relations to track the Member's available roles, I run 
into the problem that not every Member will be a Judge, so I can't just 
have a "Member.roles -> intermediateTable <- subclass" field.

Furthermore, I need to delegate to another class of Member (TourneyAdmin?) 
the ability to add/manage/remove Members and their roles, and it would be 
very convenient if the admin interface could be used for that purpose.  
However, I can write my own management screens if that turns out to be 
necessary.

I would be very grateful for suggestions on how best to handle this type of 
use case.  I'm sure it's been solved (many times) before, but it seems 
quite difficult to come up with just the right search terms to zero in on 
the right threads without a bunch of false positives.

Thank you.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.