views:

238

answers:

3

I'm new to Django and trying to implement a voting system between two images. However, it looks like the page is being cached or something because when I refresh it, some values are wrong. I have no cache setup in my Settings.

Here is the View:

def rate(request, type):
    photos = Photo.objects.order_by('?')[:2]
    c = Context({"photos": photos, "type": type})
    return render_to_response("base_rate.html", c)

and the template:

{% extends "base.html" %}

{% block body %}
<div class="photo">
    <img src="{{photos.0.photo.url}}" alt="Photo" />
    <a href="/rate/vote/{{photos.0.id}}/{{photos.1.id}}" class="vote">Vote</a>
    <a href="/rate/flag/{{photos.0.id}}" class="flag">Flag</a>
</div>

<div class="photo">
    <img src="{{photos.1.photo.url}}" alt="Photo" />
    <a href="/rate/vote/{{photos.1.id}}/{{photos.0.id}}" class="vote">Vote</a>
    <a href="/rate/flag/{{photos.1.id}}" class="flag">Flag</a>
</div>
{% endblock %}

Some pages will contain wrong info for the objects. Here is an example source that I am getting:

<div class="photo">
    <img src="/img/rate/16photo1.jpg" alt="Photo" />
    <a href="/rate/vote/16/17" class="vote">Vote</a>
    <a href="/rate/flag/16" class="flag">Flag</a>
</div>
<div class="photo">
    <img src="/img/rate/17photo2.jpg" alt="Photo" />
    <a href="/rate/vote/16/16" class="vote">Vote</a>
    <a href="/rate/flag/16" class="flag">Flag</a>
</div>

The second Vote href should be "/rate/vote/17/16" and the flag href should be "/rate/flag/17" but something is going wrong and I am getting inconsistent data.

Any ideas?

+1  A: 

order_by('?') means that the list is ordered in random order, so {{ photos.0 }} will be different each time you load the page.

Also:

<a href="/rate/vote/{{photos.1.id}}/{{photos.0.id}}" class="vote">Vote</a>
                            ^^^             ^^^

Looks like that's probably not correct.

jacobian
Yes, I am meaning to do that. I want to get two random photos to compare. The href code is ok. The first variable is the ID of the winning Photo and the second variable is the ID of the losing Photo.
Matt McCormick
This doesn't explain why the `id` is different in the second part of the same page.
Jack M.
+1  A: 

Django doesn't cache these sorts of things by default. Make sure that your browser/isp/etc. isn't caching it.

It looks like your database query isn't returning what you're expecting. Check that directly via your debugger or with print statement debugging if you have to.

That said, you really need to think long and hard about your app design. Using a GET request to make stateful changes to your app is an incredibly bad idea. Especially the way you are doing it. You need to change those links to POST requests to a single form. Otherwise, you'll find that random web spiders destroy your application.

Paul McMillan
Thanks Paul. You're right about the GET/POST. I should know that by now but I still forget every now and then.
Matt McCormick
+6  A: 

Taking a look at this in some of my code, I have this in my template:

{{ mytable.0.pk }}
{{ mytable.1.pk }}
{{ mytable.0.pk }}
{{ mytable.3.pk }}

And I get this output:

91596
54774
156800
23593

Odd, until you consider that django executes database queries very lazily. This is what shows up in my mysql log for one page load:

SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1 OFFSET 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1
SELECT `mytable`.`id` FROM `mytable` ORDER BY RAND() LIMIT 1 OFFSET 3

Each time you use the dot notation, it is executing an entire new query. I'd suggest modifying your code like so:

def rate(request, type):
    photos = list(Photo.objects.order_by('?')[:2])
    c = Context({"photos": photos, "type": type})
    return render_to_response("base_rate.html", c)

Because the list() is forcing an evaluation, it will execute the query right then and there. In addition, the data for both of those items is already cached, so there is no reason to hit the database again. You should be good to go.

Jack M.
Wow! Thanks Jack. I don't think I would have ever thought of that.
Matt McCormick
I have mysql do a full query log any time I'm working with an ORM. It helps to find those little "gotchas" that hide in most of them. It's also a good way to start optimizing ("Hey, why does that one page execute 100 queries!?").
Jack M.
The other option for this is to use the `{% with %}` template tag to force evaluation of your query. Sometimes that's more convenient than forcing it in the view.
Paul McMillan
@Paul: I tried this: `{% with stuff as stuff2 %}{{ stuff2.0.pk }}{{ stuff2.1.pk }}{{ stuff2.0.pk }}{{ stuff2.1.pk }}{% endwith %}`It still generated 4 different pk's and only 4 queries. Is there a different syntax I should have used?
Jack M.