Одна из моих моделей имеет атрибуты, которые не хранятся в базе данных. Все хорошо на уровне представления и модели, но я не могу отобразить эти атрибуты «не в базе данных» в моем шаблоне.
Вот пример кода, искусственного примера, который отражает реальную проблемную область, чтобы продемонстрировать нежелательное поведение.
Вид:
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 %}