Subclassing AbstractUser in Django for two types o

2019-04-17 04:22发布

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条回答
乱世女痞
2楼-- · 2019-04-17 05:16

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!

查看更多
登录 后发表回答