4

I'm developing a school database system in Django 1.5, and was planning on having a number of different user types (Student, Staff, Parent) which subclass AbstractUser (actually, another abstract subclass of AbstractUser). I was just attempting to add an externally developed app to my system, which uses User in a ForeignKey for some of its models, however, this fails as my user type is not a 'User' instance. I can't set the apps models to use AbstractUser as one can't use abstract classes for Foreign Keys. I was then considering adding to my settings.py AUTH_USER_MODEL = 'myapp.MyUser' and using settings.AUTH_USER_MODEL in place of User for the ForeignKey in the app. However, I have 3 different user types, so can't do this either.

An earlier prototype used Django 1.4, which did not support custom User models, hence had a reference to a User instead, but this required an extra join for every query, which was leading to quite complex queries. Is this the only way I can go forward with this, or is there another solution?

1 Answer 1

5

I have successfully used the following solution:
1. Create SchoolUser class in models.py - this will be your AUTH_USER_MODEL class

TYPES = (('Student', 'Student'), ('Staff', 'Staff'), ('Parent', 'Parent'), ) class SchoolUser(AbstractUser): type = models.CharField(max_length=10, choices=TYPES, default='Student') 

2. Create users.py file and put whole users logic there. Have one abstract class that all others inherit from and which will implement the factory method:

class UserManager(object): def __init__(self, user): self.user = user @classmethod def factory(cls, user): """ Dynamically creates user object """ if cls.__name__.startswith(user.type): # Children class naming convention is important return cls(user) for sub_cls in cls.__subclasses__(): result = sub_cls.factory(user) if result is not None: return result 

Sample children classes (also go to users.py file):

class StudentUser(UserManager): def do_something(self): pass class StaffUser(UserManager): def do_something(self): pass class ParentUser(UserManager): def do_something(self): pass 

Views is where the magic happens ;)

def my_view(request): school_user = UserManager.factory(request.user) if school_user.do_something: # each class can have different behaviour 

This way you don't need to know, which type of user it is, just implement your logic.
I hope this is clear enough, if not let me know!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.