2009-11-13 40 views
9

我的模型之一具有未存儲在數據庫中的屬性。視圖和模型級別的一切都很好,但我似乎無法在模板中顯示這些「非數據庫」屬性。使Django模型中的瞬態(非數據庫)屬性可用於模板

下面是一些示例代碼,這是一個反映實際問題域的仿真示例,用於演示不良行爲。

的觀點:

def odometer(request): 
    cars = Car.objects.all() 
    for car in cars: 
     car.read_meters() 
    context = {'cars': cars} 
    return render_to_response('odometer.html', context) 

的車型:

class Car(models.Model): 
    name = models.CharField(_('name'), max_length=100, unique=True) 

    def read_meters(self): 
     for meter in self.meter_set.all(): 
      meter.read() 

    def __unicode__(self): 
     return '%s' % self.name 

class Meter(models.Model): 
    name = models.CharField(_('name'), max_length=100) 
    car = models.ForeignKey(Car) 

    difference = 0 
    previous = 0 
    changed = False 

    def read(self): 
     # this is completely artificial. in the real application we would interface with the hardware 
     # meter to get data 
     try: 
      previous_count = MeterReading.objects.filter(meter__id=self.id).order_by('-stamp')[0].count 
     except: 
      previous_count = 0 
     self.previous = previous_count 
     current_count = previous_count 

     if (random.randrange(0, 2) == 0): 
      self.difference = int(random.random() * 100) 
      if self.name == 'Odometer' or (random.randrange(0, 2) == 0): 
       current_count += self.difference 
      else: 
       current_count -= self.difference 
       if current_count < 0: 
        current_count = 0 
     if current_count > previous_count: 
      self.changed = True 
     new_reading = MeterReading() 
     new_reading.count = current_count 
     new_reading.meter = self 
     new_reading.save() 

    def __unicode__(self): 
     return '%s' % self.name 

class MeterReading(models.Model): 
    count = models.IntegerField(_('count')) 
    stamp = models.DateTimeField(editable=False, auto_now_add=True) 
    meter = models.ForeignKey(Meter) 
    def __unicode__(self): 
     return '%s' % self.count 

而且模板:

{% for car in cars %} 
    <h2>{{ car }}</h2> 
    {% for meter in car.meter_set.all %} 
    <h3>{{ meter }}</h3> 
    <p>Difference: {{ meter.difference }}</p> 
    <p>Changed: {{ meter.changed }}</p> 
    <ul> 
     {% for reading in meter.meterreading_set.all %} 
     <li>{{ reading }}</li> 
     {% endfor %} 
    </ul> 
    {% endfor %} 
{% endfor %} 

的問題是 'meter.difference' 和 'meter.changed' 唐輸出正確的更新值。我究竟做錯了什麼?任何建議表示讚賞。

謝謝。

汽車模型:

class Car(models.Model): 
    name = models.CharField(_('name'), max_length=100, unique=True) 

    def read_meters(self): 
     for meter in self.meters: 
      meter.read() 

    def __unicode__(self): 
     return '%s' % self.name 

    @property 
    def meters(self): 
     if not hasattr(self, '_meters'): 
      self._meters = self.meter_set.all() 
     return self._meters 

而且模板:

{% for car in cars %} 
    <h2>{{ car }}</h2> 
    {% for meter in car.meters %} 
    <h3>{{ meter }}</h3> 
    <p>{{ meter.name }} difference: {{ meter.difference }}</p> 
    <p>Changed: {{ meter.changed }}</p> 
    <ul> 
     {% for reading in meter.meterreading_set.all %} 
     <li>{{ reading }}</li> 
     {% endfor %} 
    </ul> 
    {% endfor %} 
{% endfor %} 

回答

11

您在模板中看不到這些值的原因是每次調用car.meter_set.all()時,都會直接從數據庫中獲取全新的查詢集。

Django模型實例沒有標識,因此即使一個查詢集中的對象具有與另一個查詢集中的對象相同的數據庫值,它們也不共享任何動態屬性。

做到這一點的一種方法是緩存每輛車內的儀表對象,因爲我在最近的問題上顯示here。然後,而不是在視圖,模型和模板中引用car.meter_set.all(),您將執行car.get_meters()或其他任何操作,並且每次都會獲得同一組對象以及動態屬性。

+0

真棒謝謝你。 – 2009-11-13 13:36:57

1

我想類似的東西在我自己的代碼,它看起來

更新:根據丹尼爾的回答更新代碼像您遇到的問題發生在read_meter()方法和odomoter()視圖中。

metercar您用於迭代查詢集的對象已經超出了範圍,並且您對其屬性所做的更改也隨之發生。

當您在模板中顯示meter.difference和meter.changed時,Django會從數據庫(並且沒有未保存的屬性值)重新創建這些對象。

希望解釋清楚。任何不將值保存到數據庫的理由?

+0

我不保存數據的原因很簡單,它是暫時的。對我來說,存儲數據必須在運行中計算並且永遠不會在數據庫字段中再次引用,這似乎是錯誤的。請注意,上面的例子是假的,在實際應用中,一些瞬態數據的大小是數百MB。謝謝你的幫助。 – 2009-11-13 23:03:42