2013-07-09 75 views
1

我試圖實現一個投票系統,爲我的網站上每種類型的用戶保持跟蹤投票。我的計劃是創建一個投票模型,記錄每個用戶類型的最多投票和總投票數,並計算最多投票的百分比。Django - 在模型中動態創建字段名稱(字段不保存)

硬編碼的,看起來是這樣的:

class Eduuser(AbstractUser): 
    TYPE_1 = 'TY1' 
    TYPE_2 = 'TY2' 
    ... 

    USER_TYPE_CHOICES = (
     (TYPE_1, 'Type 1'), 
     (TYPE_2, 'Type 2'), 
     ... 
    ) 
    user_type = models.CharField(max_length=3, choices=USER_TYPE_CHOICES) 


class Vote(models.Model): 

    a = models.IntegerField(
     default=0, name=getattr(Eduuser, 'TYPE_1')+'_up') 
    b = models.IntegerField(
     default=0, name=getattr(Eduuser, 'TYPE_2')+'_up') 
    ... 

    c = models.IntegerField(
     default=0, name=getattr(Eduuser, 'TYPE_1')+'_votes') 
    d = models.IntegerField(
     default=0, name=getattr(Eduuser, 'TYPE_2')+'_votes') 
    ... 

    def perc(self): 
     perc_array = [] 
     for user_type in getattr(Eduuser, 'USER_TYPE_CHOICES'): 
      up = float(getattr(self, user_type[0]+'_up')) #Prevent int division 
      votes = getattr(self, user_type[0]+'_votes') 
      if votes==0: 
       perc_array.append(0) 
      else: 
       perc_array.append(round(up/votes, 3)) 
     return perc_array 

雖然我並不預期增加更多的類型,我想的代碼看起來更乾淨。我最好的嘗試循環用戶類型是:

class Eduuser(AbstractUser): 
    ... 

class Vote(models.Model): 
    for user_type in getattr(Eduuser, 'USER_TYPE_CHOICES'): 
     models.IntegerField(
      default=0, name=user_type[0]+'_up') 
     models.IntegerField(
      default=0, name=user_type[0]+'_votes') 

    def perc(self): 
     ... 

但是這並不保存字段(我猜是因爲缺乏賦值運算符)。 所以有幾個簡單的問題:

1)有沒有一種方法可以保存字段,而不必明確指定它們的名稱?或者我可以將字符串名稱轉換爲一個變量(從我讀過的其他帖子看,這似乎是一個壞主意)?

2)我是否在邏輯上接近這個投票想法?我的一部分感覺像是有一種更容易的方法來跟蹤多種類型用戶的投票。

任何幫助表示讚賞!謝謝!

回答

1

django-model-utils可以使它更清潔它的選擇幫手。

你可以做以下方式Vote模型(未經測試):

from model_utils import Choices 


class User(AbstractUser): 
    USER_CHOICES = Choices(
     ('one', 'Type 1'), 
     ('two', 'Type 2'), 
    ) 

    user_type = models.CharField(max_length=10, choices=USER_CHOICES) 


class Vote(models.Model): 
    """ 
    A single vote on a `User`. Can be up or down. 
    """ 
    VOTE_CHOICES = Choices(
     ('upvote'), 
     ('downvote'), 
    ) 

    user = models.ForeignKey(User) 
    vote = models.CharField(max_length=10, choices=VOTE_CHOICES) 

用法示例 - 獲得的贊成票數全部爲「1型」用戶:

# retrieve all of the votes 
all_votes = Vote.objects.all() 
all_votes_count = len(all_votes) 

# now retrieve all of the votes for users of ‘Type 1’  
type_one_votes = all_votes.filter(user__user_type=User.USER_CHOICES.one) 
type_one_votes_count = len(type_one_votes) 

# …and now filter the positive votes for ‘Type 1’ users 
type_one_positives = type_one_votes.filter(vote=Vote.VOTE_CHOICES.upvote) 
type_one_positive_vote_count = len(type_one_positives) 

# etc. 
+0

非常有幫助,'選擇'是我以前沒見過的一個有用的工具。我知道我的方式太複雜了...... – chipperdrew

0

Django根據您聲明的內容使用一些元類行爲來創建字段,因此這不是微不足道的。還有,你可以用它來動態字段添加到你的模型類的一些未公開的電話 - 看到這個帖子:

http://blog.jupo.org/2011/11/10/django-model-field-injection/

這就是說,我會建議一個更簡單的方法。創建一個模型來保存可能的用戶類型,然後使用它作爲投票表的外鍵:

class UserType(models.Model): 
    type_name = models.CharField() 

class Vote(models.Model): 
    user_type = models.ForeignKey(UserType) 
    total = models.PositiveIntegerField() 

或根據需要跟蹤個人票和總和,無論是記錄誰投的票也好,還是用戶用戶在投票時的類型。如果用戶在投票後更改類,則可能需要保存用戶的類型,具體取決於您想要執行的操作。

如果你只是跟蹤總和,你必須更仔細地考慮事務問題 - 我會說跟蹤用戶並強制執行唯一性約束。

+0

也很好的答案。我沒有想過用戶切換類型,非常有用的考慮。非常感謝! – chipperdrew