2010-05-08 131 views
1

我正在做一些效率不高的事情。從我下面的代碼中,你可能會看到我試圖允許將多個不同類型的配置文件附加到我的自定義用戶對象(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") 

回答

2

所有你可以做的事情很多更容易通過不聲明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?你可以做這樣的事情:

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

此外,我希望你沒有使用USER_TYPE領域僅用於這個目的,因爲Django的已建成它更好的,你可以看到。我也希望你的派生配置文件類中還有其他一些獨特的字段,否則你應該把它們扔掉,然後通過一個usertype字段放到BaseProfile中(查看choices來做到這一點)。

現在至於is_default,恕我直言,這種方法是一樣好。你總是可以嘗試添加自定義約束到你自己的dbms,說應該有0或1個記錄包含相同的FK和is_default = True(沒有django的方式來做到這一點)。我還要說的是,添加一個make_default方法,並在該方法中確保is_default對該人是唯一的(例如,首先在具有相同FK的所有配置文件上將is_default設置爲False)。這會爲你節省很多可能的傷痛。您也可以在BaseProfile的save()方法中添加此檢查。

另一種可以做到這一點的方法是將外鍵添加到指向默認配置文件的人員模型。雖然這將確保默認在django級別上是唯一的,但它也可以提供數據的非規範化和損壞,即使在更令人討厭的級別上,所以我並不是很喜歡它。但是,如果您通過預定義的方法添加/刪除/更新配置文件(現在會更復雜!),您應該是安全的。

最後,也許你有充分的理由繼承用戶,但擴展用戶功能的默認方式不是這樣,它的描述爲here

+0

我已經避免從BaseProfile中移除抽象,希望在模板中到達我的「類型」配置文件之前不必穿過另一個層。然而,我錯過的那個謎題的缺失部分是在模型上創建訪問器,從模板中遮蓋了該圖層。 現在我看到,走這條路線開闢了一系列更好的方式來做到這一點,這正是我所期待的。我會嘗試這種方法,謝謝Killian! – Scott 2010-05-08 16:43:39

相關問題