2015-10-14 111 views
1

我有一個普通用戶,誰擁有一些測量,每一種都可以有一個或多個標籤的結果:獲取相關對象

class User(AbstractBaseUser): 
    born = models.DateField(null=True, blank=True) 
    ... 

class Measurement(models.Model): 
    user = models.ForeignKey(User, related_name='measurements') 
    ... 

class MeasurementResult(models.Model): 
    measurement = models.ForeignKey(Measurement, related_name='results') 
    tag = models.CharField(max_length=255) 
    value = models.FloatField() 
    ... 

我想獲得的所有用戶,所有的測量,並與標籤所有結果,這樣我可以做到以下幾點:

{% for user in users %} 
<div class="row"> 
    <div class="col-md-4">{{user.name}}, {{user.age}}</div> 
    <div class="col-md-4">{{user.tags}}</div> 
    <div class="col-md-4"><a href="{% url 'user_detail' user.id %}"> View detail</a></div> 
</div> 
{% endfor %} 

我這裏有一些問題,我不知道如何正確解決:

  • user.age:我沒有用戶的年齡,但是用戶出生的日期。我如何將一個從數據庫中的天生屬性派生的age屬性添加到queryset中的用戶?
  • user.tags:這比較棘手,因爲標籤是從給定用戶的所有測量結果的所有標籤的聯合(集合)中獲得的。我想我需要爲此使用註釋,但不知道如何去做。

目前的年齡我已經添加了一個方法,將User型號:

class User(AbstractBaseUser): 
    ... 
    def age(self): 
     '''Returns the age of this user''' 
     if not self.born: 
      return None 
     today = date.today() 
     return today.year - born.year - ((today.month, today.day) < (born.month, born.day)) 

這是添加一個屬性到模型的正確,也可能?通過添加一個方法?或者是更好的Django方式這樣做嗎?

並添加標籤,我有一個簡單的輔助功能,它增加了一個屬性爲每個用戶:

def get_users_with_tags(skip_user=None): 
    '''Lists all users, adding to each user the measurements results' tags''' 
    users = User.objects.all() 
    if skip_user: 
     users = users.exclude(pk=skip_user.id) 
    for user in users: 
     measurements = Measurement.objects.filter(user=user.id) 
     tags = set() 
     for measurement in measurements: 
      results = MeasurementResult.objects.filter(measurement=measurement) 
      for result in results: 
       tags.add(result.tag) 
     user.tags = ','.join(list(tags)) 
    return users 

但我不喜歡,我要求每個用戶的測量,結果爲每次測量。有沒有辦法在單個數據庫訪問中獲得所有這些?我不喜歡user.tags ad-hoc屬性添加這樣。有沒有更好的方法來做到這一點? UserManager也許,但如何訪問Model Manager中的相關模型?

什麼都可以歸結爲是,即使由get_users_with_tags返回的值是通過上述Django模板非常有用的,這些相同的結果是不可用的(不可序列,因爲他們是不是一個真正的QuerySet?)對一個Django rest API。

我想改進該函數,以便產生可供django模板和django rest API框架使用的結果。

回答

2

我覺得對於這兩種情況你可以使用屬性裝飾器;

class User(AbstractBaseUser): 
born = models.DateField(null=True, blank=True) 
..... 

@property 
def age(self): 
    '''Returns the age of this user''' 
    if not self.born: 
     return None 
    today = date.today() 
    return today.year - born.year - ((today.month, today.day) < (born.month, born.day)) 


@property 
def tags(self): 
    '''Returns the tags of this user''' 
    return MeasurementResult.objects.filter(measurement_id__in=self.measurements.all().values_list('id', flat=True)).distinct().values_list('tag', flat=True) 

在這裏,您將獲得的標籤

+1

甚至不需要成爲財產目錄,因爲Django的模板標籤將識別與OP的當前模板代碼 – Sayse

+0

事實上的方法;無論如何,這裏是屬性裝飾鏈接:https://docs.python.org/2/library/functions.html#property – Wtower

+0

@Sayse,我很困惑:我需要聲明它作爲屬性爲它在任何工作背景?我的意思是,不僅在模板上下文中,而且在串行器上下文中。 – dangonfast