代码之家  ›  专栏  ›  技术社区  ›  Scott

如何处理每个用户的多个配置文件?

  •  1
  • Scott  · 技术社区  · 15 年前

    我在做一些感觉不太有效的事情。从下面的代码中,您可能会看到我正试图允许将不同类型的多个配置文件附加到我的自定义用户对象(Person)上。其中一个配置文件将被视为默认配置文件,并且应该具有来自Person类的访问器。存储一个 is_default 配置文件上的字段似乎不是跟踪默认值的最佳方法,是吗?

    from django.db import models
    from django.contrib.auth.models import User, UserManager
    
    
    class Person(User):
    
        public_name = models.CharField(max_length=24, default="Mr. T")
    
        objects = UserManager()
    
        def save(self):
            self.set_password(self.password)
            super(Person, self).save()
    
    
        def _getDefaultProfile(self):
    
            def_teacher = self.teacher_set.filter(default=True)
            if def_teacher: return def_teacher[0]
    
            def_student = self.student_set.filter(default=True)
            if def_student: return def_student[0]
    
            def_parent  = self.parent_set.filter(default=True)
            if def_parent:  return def_parent[0]
    
            return False
        profile = property(_getDefaultProfile)
    
    
        def _getProfiles(self):
            # Inefficient use of QuerySet here. Tolerated because the QuerySets should be very small.
            profiles = []
            if self.teacher_set.count(): profiles.append(list(self.teacher_set.all()))
            if self.student_set.count(): profiles.append(list(self.student_set.all()))
            if self.parent_set.count():  profiles.append(list(self.parent_set.all()))
    
            return profiles
        profiles = property(_getProfiles)
    
    
    
    
    class BaseProfile(models.Model):
    
        person = models.ForeignKey(Person)
        is_default = models.BooleanField(default=False)
    
        class Meta:
            abstract = True
    
    
    class Teacher(BaseProfile):
        user_type = models.CharField(max_length=7, default="teacher")
    
    
    class Student(BaseProfile):
        user_type = models.CharField(max_length=7, default="student")
    
    
    class Parent(BaseProfile):
        user_type = models.CharField(max_length=7, default="parent")
    
    1 回复  |  直到 15 年前
        1
  •  2
  •   KillianDS    15 年前

    首先,通过不声明baseprofile抽象,可以使事情变得更简单:

    from django.db import models
    from django.contrib.auth.models import User, UserManager
    
    class Person(User):
        public_name = models.CharField(max_length=24, default="Mr. T")
        objects = UserManager()
    
        def save(self):
            self.set_password(self.password)
            super(Person, self).save()
    
        def _getDefaultProfile(self):
            try:
                return self.baseprofile_set.get(default=True)
            except ObjectDoesNotExist:
                return False
        profile = property(_getDefaultProfile)
    
        def _getProfiles(self):
            return self.baseprofile_set.all()
        profiles = property(_getProfiles)
    
    class BaseProfile(models.Model):
    
        person = models.ForeignKey(Person)
        is_default = models.BooleanField(default=False)    
    
    class Teacher(BaseProfile):
        user_type = models.CharField(max_length=7, default="teacher")    
    
    class Student(BaseProfile):
        user_type = models.CharField(max_length=7, default="student")    
    
    class Parent(BaseProfile):
        user_type = models.CharField(max_length=7, default="parent")
    

    这样更好吗?你的属性不知道它们返回的是什么类型,所以抽象基类只会让你在那里有一个令人难以置信的烦人开销。

    如果你现在想知道,既然我做了任何返回的baseprofile,你怎么能从特定的profile中得到数据?你可以这样做:

    try:
        #note the lowercase teacher referal
        print myuser.profile.teacher.someteacherfield 
    except Teacher.DoesNotExist:
        print "this is not a teacher object!"
    

    另外,我也希望您不要仅仅为了这个目的而使用用户类型字段,因为django有更好的内置功能,如您所见。我还希望在派生的概要文件类中确实有一些其他独特的字段,因为否则,您应该将它们丢弃,并将其通过一个用户类型字段进入baseprofile(请看 choices 做这件事)。

    至于默认值,imho这个方法和其他方法一样好。您总是可以尝试将自定义约束添加到DBMS本身,即应该有0或1个包含相同FK的记录,并且默认值为“真”(没有Django方法可以做到这一点)。我还想说的是,添加一个方法使其成为默认值,在该方法中,确保“默认值”对该人是唯一的(例如,通过第一次设置,在具有相同FK的所有配置文件上,“默认值”为“假”)。这会让你省去很多可能的悲伤。您还可以在baseprofile的save()方法中添加此检查。

    另一种方法是向指向默认配置文件的人员模型添加外键。虽然这将确保默认值在Django级别上是唯一的,但它也可以提供数据的非规范化和损坏,甚至在更烦人的级别上,所以我不太喜欢它。但同样,如果您通过预定义的方法添加/删除/更新概要文件(现在会更复杂!)你应该安全。

    最后,也许您有很好的理由从用户继承,但是扩展用户功能的默认方法不是这样的,它已经描述过了。 here .

    推荐文章