English 中文(简体)
Making transient (non-database) attributes in Django model available to template
原标题:

One of my models has attributes that are not stored in the database. Everything is fine at the view and model level but I cannot seem to display these non-database attributes in my template.

Here s some example code, an artificial example that mirrors the actual problem domain, to demonstrate the undesired behavior.

The view:

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

The models:

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

And the template:

{% 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 %}

The problem is meter.difference and meter.changed don t output the correct updated values. What am I doing wrong? Any advice is appreciated.

Thanks.

UPDATE: Updated code based on Daniel s answer:

The Car model:

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

And the template:

{% 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 %}
最佳回答

The reason why you aren t seeing these values in your template is that every time you call car.meter_set.all() you get a completely new queryset straight from the database.

Django model instances don t have identity, so even though the Meter objects in one queryset have the same database values as the ones in another, they do not share any dynamic attributes.

One way to do this would be to cache the Meter objects within each Car, as I show here on a recent question. Then instead of referring to car.meter_set.all() in the view, model and template, you would do car.get_meters() or whatever, and you would get the same set of objects each time, along with your dynamic attributes.

问题回答

I tried something similar in my own code and it looks like the problem you re running into is happening in the read_meter() method and odomoter() view.

The meter and car objects that you re using to iterate through the QuerySets are falling out of scope, and the changes you make to their attributes is going with them.

When you display meter.difference and meter.changed in the template, Django s recreating those objects from the DB (and without the unsaved attribute values).

Hope that explanation is clear. Any reason not to save the values to the DB?





相关问题
Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

JSON with classes?

Is there a standardized way to store classes in JSON, and then converting them back into classes again from a string? For example, I might have an array of objects of type Questions. I d like to ...

Object-Oriented Perl constructor syntax and named parameters

I m a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot. package Foo; #In Perl, the constructor is just a subroutine called new. sub new { #I ...

Passing another class amongst instances

I was wondering what is the best practice re. passing (another class) amongst two instances of the same class (lets call this Primary ). So, essentially in the constructor for the first, i can ...

Where can I find object-oriented Perl tutorials? [closed]

A Google search yields a number of results - but which ones are the best? The Perl site appears to contain two - perlboot and perltoot. I m reading these now, but what else is out there? Note: I ve ...

热门标签