2009-11-13 5 views
9

私のモデルの1つに、データベースに格納されていない属性があります。すべてのビューとモデルレベルでは問題ありませんが、私は私のテンプレートにこれらの '非データベース'の属性を表示するように見えることはできません。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' ドン正しい更新値を出力しません。私は間違って何をしていますか?アドバイスをいただければ幸いです。

ありがとうございました。

UPDATE:ダニエルの答えに基づいて更新されたコード:

車種:

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モデルのインスタンスにはIDがないため、あるクエリーセット内のMeterオブジェクトは同じデータベース値を持ちますが、動的属性は共有されません。

最近の質問にhereと表示されているように、これを行う1つの方法は、各車内にMeterオブジェクトをキャッシュすることです。次に、ビュー、モデル、テンプレート内でcar.meter_set.all()を参照する代わりに、car.get_meters()などを実行し、毎回ダイナミックアトリビュートとともに同じオブジェクトセットを取得します。

+0

ありがとうございます。 –

1

私は自分のコードで同様の何かをしようと、それが見えます実行中の問題がread_meter()メソッドとodomoter()ビューで発生しているようです。

car QuerySetsを繰り返し処理するために使用しているオブジェクトが範囲外になり、その属性に加えられた変更がそれらに反映されます。

テンプレートにmeter.differenceとmeter.changedを表示すると、DjangoはそれらのオブジェクトをDBから(未保存の属性値なしで)再作成します。

その説明は明らかです。値をDBに保存しない理由は何ですか?

+0

私がデータを保存しない理由は、それが一時的であるということだけです。その場で計算しなければならないデータを格納するのは間違っているようで、データベースフィールドで再び参照されることはありません。上記の例は人為的なものであり、実際のアプリケーションでは一時的なデータの中には数百MBのサイズがあることにも注意してください。ご協力いただきありがとうございます。 –

関連する問題