Creating / Generating a URL Friendly Snippet in Django

When generating URLs that say something about the content it contains, you usually have the need to create url-friendly strings (such as “creating-generating-a-url-friendly-snippet-in-django” for this post). Earlier today I had the need build something like that in Django, but came up empty handed for a while – simply because I didn’t realize that they’re called slugs in the Django documentation (which in turn inherited it from the print paper world). That helped quite a bit, and here’s the things you need to know:

If you want your model to perform validation and automagically add a database index for the slug, put in a SlugField in your model. You could use a regular CharField, but this will not provide any validation of the field in the admin interface (and you’d have to add db_index yourself). This will however not populate the field with a value, but this stack overflow question has a few pointers on how you could implement that. I’ll cite the interesting parts here:

from django.template.defaultfilters import slugify

class test(models.Model):
    q = models.CharField(max_length=30)
    s = models.SlugField()

    def save(self, *args, **kwargs):
        if not self.id:
            self.s = slugify(self.q)

        super(test, self).save(*args, **kwargs)

This will populate the slug field the first time the entry is saved, and will not update the slug value if the object itself is updated.

You can however also handle this yourself in the get_absolute_url of your object, if you don’t need to perform any lookups on the value (although you could still save it to avoid regenerating it later). This will also give you the current slug for the entry (again, if you only use it as a part of the URL and do not validate it in any way):

from django.template.defaultfilters import slugify

def test(models.Model):
    q = models.CharField(max_length=30)

    @models.permalink
    def get_absolute_url(self):
        return ('reviewerer.views.sites_detail', [str(self.id), slugify(self.q)])

Hopefully that will help you solve your issue .. or at least search for the correct term next time :-)

Varnish: No ESI processing, first char not ‘<‘

I’ve spent some time setting up varnish for a service at work where we deliver JSON-fragments from different resources as a unified document. We build the resulting JSON document by including the different JSON fragments through an ESI (Edge Side Includes) statement in the response. Varnish then fetches these fragments from the different services, allowing for independent caching duration for each of the services, combining then into a complete document.

The main “problem” is that of Varnish 2.0.4, varnish does a check to see if the content returned from the server actually is HTML-based content. It does this by check if the first character of the returned document is ‘<'. The goal is to avoid including binary data directly into a text document. Since we’re working with JSON instead of regular HTML/XML, the first character in our responses is not a ‘<', and the ESI statement did not get evaluated. You can however disable this check in varnishd by changing the esi_syntax configuration setting - just add the preferred value to the arguments when starting varnish. To disable the content check, add:

varnishd … -p esi_syntax=0x1

I’m not sure if you can set this for just one handler / match in varnish as this solved our issue, but feel free to leave a comment if you have any experience with this.

A couple of issues with SWFUpload 2.5.0b1

The first beta of SWFUpload 2.5.0 was released during christmas, and just a few quick notes for those who are going to attempt an upgrade:

button_cursor: SWFUpload.CURSOR.HAND,

.. seems broken. This will probably be fixed soon, but currently I’ve been unable to get the proper mouse cursor for a button.

If you previously relied on any custom settings being available in the settings object (by providing them when initializing the component), SWFUpload 2.5.0 does not include them in the this.settings object any longer.

If you want to include any custom settings, they’ll now have to be included in a setting for that purpose (together with the other options in the settings object):

swfu = new SWFUpload({
    [settings settings]
    custom_settings : {
        redirect : true,
        redirect_delay : 500
    },
    [more settings]
});

These values will then be availble through this.settings.custom_settings in your callback functions, such as this.settings.custom_settings.redirect etc.

Both issues has been reported on the v2.5.0b1 announcement.

Avoiding Resetting the Scroll Position in a Textarea When Inserting Content

Now, that’s quite a headline. And this post will explain just the simple concept posted in the headline. How to avoid (at least) firefox from scrolling to the top when you insert content into a textarea.

It’s simple. Very simple. And it was shown to be so very simple for someone who didn’t remember scrollTop by this thread.

In jQuery (which we use with the caret plugin):

currentScrollPosition = $("#textareaId").scrollTop();
/* do stuff */
$("#textareaId").scrollTop(currentScrollPosition);

Yep. So simple that it actually hurts a bit.

Content License Change

Just a friendly reminder that I’ve now changed the license of the content on this blog to a much more friendly Creative Commons-based license, namely the “Do what the hell you want, but remember to link back and tell people who wrote it”. I’ve been using the license for the majority of my photos during the last years, so it’s a natural evolution. Have fun!

Borked Behaviour for the Back-button in Firefox

I investigated a strange problem yesterday, where the back button in Firefox returned the user to the top of the previous page, instead of to the location where he already had scrolled. The problem seemed to have brought its fair share of problems for developers all over, and a thread detailing the problem in Drupal provided the information needed to solve it. The problem is actually so wide-spread that there is a dedicated Firefox extension to solve the issue (Restore Scroll Position).

Anyways, the issue stems from the Cache-Control headers that PHP among others include by default:


Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

The problem is that the “no-store” directive tells the browser do NOT store a version of the page anywhere, not temporarily, not .. ever. Internet Explorer and Opera still remembers the position, but Firefox decided to take everything a step further and does not keep any information available. The extension mentioned above saves the scroll position in another location and then restores the scroll position after navigating back to the page.

The problem is solved by changing the Cache-Control header:


Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0

A very helpful tip here is that you probably need to restart Firefox to make it respect the new header, as it will keep its old behavior until you restart the browser (at least for Firefox 3.0.6).

Internet Explorer 8 and Their XSS Filter

There’s an interesting post up on the technet Security Vulnerability Research & Defense blog, providing a deeper look into how the XSS filter destined for release together with Internet Explorer 8 works. While it looks like a novel approach, I’m not sure how many of the actual attacks will be detected and guarded against. It will be interesting to get to play around with it later, and if it works as good as they say, it’ll provide some protection for the users of Internet Explorer against a class of attacks.

They provide several examples of issues that will not be mitigated by this filter, which includes attacks where the content is inserted directly into javascript (instead of spawning from an HTML-context).

TinyMCE and {#advanced_dlg.link_url}

If you ever get {#advanced_dlg.link_url} (and similar values, such as {#advanced_dlg.link_list}, {#advanced_dlg.link_target} or {#advanced_dlg.link_titlefield}) in your advanced theme link window in TinyMCE, the language file has not been loaded properly. The two simplest reasons for this is that the language file may be missing completely, or that you’ve provided a language key that does not exist. To check for the first issue, check that you have en_dlg.js in your themes/advanced/langs/ directory. To check for the other issue, try to set the language parameter (when creatinging the TinyMCE object) to ‘en‘ just to test it with the default value. If it works with ‘en’, you’re probably missing the local translation file for the advanced theme. Get it from the TinyMCE site and live happily ever after!