Archive for February, 2007

Django trap with LIMIT queries

I started doing Django after the magic-removal, but there is some magic left (but mostly good magic) in it and it’s a good thing to be aware of it! Always dig deeper, that’s at least my motto.

The model used here is the following:


class Item(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(maxlength=100)
    def __str__(self):
        return self.name

The LIMIT basics
Be sure to really understand what happens when you are using limit query, which is the array slicing syntax. Calling the following:
Item.objects.all()[2:4]
will execute this query
SELECT `core_item`.`id`,`core_item`.`name` FROM `core_item` LIMIT 2,2
BUT not until you are using the data. Using the shell is therefore sometimes a bit misleading, since calling the above results in printing the result, so it is being used at this moment, which inside a script would not be the case.

>>> Item.objects.all()[2:4]
[, ]

Here you can see that two items are being printed, right after the call, but that’s a shell thing, remember that!

Mixing slicing and LIMIT
If you mix the usage of the slicing operator and the limit query on a queryset you better know what you are doing. Let’s see first:

>>> items = Item.objects.all()[2:4] # Django basics, this is LIMIT.
>>> items[5] # Looks like it should be slicing, is LIMIT!


Ooops. How come? Why is there a fifth element at all? Let’s investigate a bit more! Is items not what we expect? How many elements does items contain? What is being returned, when calling the first line of the above?

>>> len(items)
2
>>> type(items)


Uhu, ok. The Django documentation does also explain that very well, so be aware, you don’t get a list returned, but a queryset!
So what is happening here in detail? This line >>> items = Item.objects.all()[2:4] clones a queryset into the variable items. So items is not a list, as the syntax might would let you expect, but a queryset! This assignment is actually only a method call. The method call to __getitem__() in django.db.model.query.QuerySet, this does finally return a cloned queryset with adjusted LIMIT parameters (effectively this is called self._clone(_offset=offset, _limit=limit)). So there is no query execution at this point.
And if the next call is now items[5] then the same method is being called again with LIMIT 5. So there is no slicing done here, as one would expect. This second call is also just a simple method call to __getitem__() and since the shell prints the result right away the query is actually being fired!

The work around
In order to make Django do what you expect you need to be more explicit than normally:

>>> items = list(Item.objects.all()[2:4])
>>> items[0]

>>> type(items)


This makes Django fire the query right away and return a real list, as you can see above. Now you can use the result as one would expect when reading it as normal Python code (without knowing that it is Django).
This has two effects: you are executing the query earlier and you have no QuerySet object anymore that you can work with. But that might be intended in this case.

Summary

>>> # next line fires: SELECT * FROM `core_item` LIMIT 2,2
>>> Item.objects.all()[2:4]
[, ]
>>> items = Item.objects.all()[2:4] # fires no query!
>>> # next line fires: SELECT * FROM `core_item` LIMIT 1
>>> items[0]


But

>>> items = list(Item.objects.all()[2:4]) # fires: SELECT * FROM `core_item` LIMIT 2,2
>>> items[0]


As I have mentioned above, you better know your tools! Django is very nicely using the overriding facilities that Python offers, but as usual, when you only scratch the surface you might be surprised and think “What is happening here” but don’t worry, the engine below is well thought through and really powerful! Let’s keep Djangoing …

Update
Thanks for Martina’s comment, which of course makes it much better! I modified the article accordingly.

Comments (5)

IE reloads images way too often

Oh yes, that had hit me quite often too. Even though I was only using a background-image in my simple CSS:

a.section {
background-image:url(/img/arrow-right1.gif);
background-repeat:no-repeat;
background-position:center left;
}
a.section.open {
background-image:url(/img/arrow-down1.gif);
}

As you can see, when I add the class “open” to an element, the background image is replaced with another one. IE unfortunately does a server request for this image every time. How dumb!

Here is an extensive article, covering and solving this problem. Unfortunately there is no client side fix, you gotta touch the server.

Comments

WingIDE and encoding

WingIDE tries to be clever and interprets the charset I use in my HTML file. So this makes it pretty happy:



But if I want to use this:


... content="text/html;charset={{ DEFAULT_CHARSET }}" />

It tells me:

Unsupported encoding ‘{{ default_charset }}’ found in encoding comment — Wing cannot write this file until the comment is changed

Well that is pretty funny. So I can’t use the Django setting to determine my charset.
Even turning off WingIDE’s file property “Use charset from file” (or what it is called) doesn’t help. Just in case someone is struggling too.

Comments (2)

Good to have: Universal Encoding Detector

By Mark Pilgrim, to get here http://chardet.feedparser.org/.

Comments (1)

Django and UTF8

I have to deal with it now and a lot of other people too, judging by the utf8/unicode/encoding topics on the django mailing list. I have found this one thread quite interesting and looks like the problem solver, but may be I also just need to learn a bit more about the bits and pieces that make this whole thing work. This message obviously tells how to make mysql completely aware and well-handling utf8.
Next thing on the list the django setting parameter DEFAULT_CHARSET.

Comments (2)

Convert MySQL table to utf8

Read here how to change all your DB to utf8, pretty simple, but you gotta know it. Even when your app runs in latin1 only, it reduces a couple problems in case you forgot some check and utf8 is slipping through. I will let you know if I can prove that right. But since Django is trying to be unicode compliant, it’s easier to use it than to work around it.
It does at least already eliminate the problem of getting this error:

Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE)

this was discussed here.
In short:

ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

Comments (6)

Make IE crash

Since IE (version 6) is still widely used, sad enough, we have to make things work there. The Microsoft devs had not been friendly by releasing this monster. Geee, there are enough things that make IE crash and now I am searching for the reason why mine crashes when it receives a back tick as content somewhere or if the reason is another, but surely it’s the content of the page. If that takes so long it’s no fun anymore, I am just searching the web for how to solve this and that problem.
Also I let dojo do some eye candy but as usual IE makes it a problem. I guess my layout structure is too complex for the IE, so I will probably need to use less margins and floats for the main content elements. It doesn’t get boring :-)

Comments