Tag Archives: django

Libraries gave us power

After living in the area for seven years or so, I noticed Rawdon Library the other day. It’s a fairly utilitarian bit of civic architecture, built in limestone and in sight of the A65 in the corner of Micklefield Park. It’s one of the libraries in Leeds that is earmarked for closure as part of the city’s New Chapter reorganisation and of the four in the area would appear to be the one that is most likely to close, being both relatively close to Yeadon and Guiseley libraries and quite a way from what most people would regard as Rawdon, and as such is not able to meet one of the main functions of a library, that of a community resource.

Libraries are some of the more visible resources of the municipal landscape as they are public buildings as much as they are book repositories, and therefore when they are perceived as being at risk, concerned people get together to support them. However, many of those concerned people are probably trying to save something that they remember from their childhood, and not what they are now.

Those of us who are in our forties were probably the last generation that really knew what the public libraries were. As we left school they started to be eroded by the cuts that eroded the visible aspects of public service in the 80s and 90s. Books got old and were not replaced: populism replaced service and videos and DVDs joined cassettes and CDs. The Internet brought PCs into a corner of the building and then took over when Amazon made books more easily available then any library could make them.

The libraries that are under threat now are therefore not the libraries that we think they are. Yes, they are an excellent resource, but making books available is not their primary function: they are social centres and meeting places, and as such should be preserved, but much of the goodwill surrounding them is due in part to the nostalgia of our generation.
However, let us also not forget where the British public library came from: many were founded on the bequest of the Carnegie Foundation: the kind of philanthropy that the modern Conservative Party (or its leadership at least) believes should be the foundation of the Big Society, but which in truth, would never exist in this way again.

Advertisements

User communication with Django Messages and jGrowl

Like any good web application, I wanted stocklotstv/vidjyo to have a method of sending messages to the user. Simple stuff like ‘invalid username and password’ or a friendly greeting when the user succeeded in logging in, that sort of thing.

This requirement has now been added to django with the inclusion of django.contrib.messages in version 1.2. There has been a messaging framework included in django.contrib.auth since early days, but there are situations when you don’t want to use the native auth system, but you do need messaging, so it has been repackaged and extended as a standalone contribution.

The instructions for adding messages to your application are documented at Django Advent
Using the code is pretty simple. Add django.contrib.messages to your view or function and pass messages into the request context:

message.info(request, 'You have logged in')

and make sure that you are sending the request context to your templates (you *are* sending the request context to your templates aren’t you? It should be the default action in my opinion, but hey, that’s me, what do I know).

The template example at Django Advent is pretty simple -put this code somewhere in your templates:

{% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
        {% endfor %}
    </ul>
{% endif %}

However, I, and probably you, want to have system messages on most, if not all of our pages, so if you have a standard template layout, with a base template that includes the page metadata, and blocks or includes for header, footer and content, put the code in the html body, below your header but above your content.
What you get is an unsorted list of system messages at the top of your page, which probably isn’t what you want.

You could have some fun with CSS and turn your list into a menu or a sequence of messages, but a more common method of display these days, in the civilised worlds of Linux and Mac OS X at least, is to display the messages as bubbles, usually in the corner of the screen. In OS X, this is enabled by a system called Growl, which provides cross platform messaging with a very nice UI. On the web, it has been emulated with a couple of the better javascript libraries and as I have been mostly working with jQuery, I found jGrowl.

This is pretty simple to get working by following the demos, but they only cover getting messages by clicking on a link. What we want is for the messages to pop up when the page loads. This is where jQuery’s

$(document).ready(function())

comes in. This loads any script item in it when the document model is ready (sorry if that’s not wholly accurate, but that’s how I read it). Drupal has a jGrowl module that provides messaging in this way, so with a bit of code reading and lateral thinking, I came up with this:

{% if messages %}
<link href="/media/css/jquery.jgrowl.css" type="text/css" rel="stylesheet" media="screen" />
	<script type="text/javascript">
	(function($) {
		$(document).ready(function(){
			{% for message in messages %}
				$.jGrowl("{{ message }}");
			{% endfor %}
		});
	})(jQuery);
</script>

{% endif %}

Put simply, if there are messages in the request context, the browser will pass them into jGrowl and display them. There is no styling there at the moment, so they pop up at top right of the screen as white text on a black background. To save browser resources I also don’t load the stylesheet unless there are messages.
My next step is going to be to set the default position to centre and possibly to redesign the layout. jGrowl has a theme setting which is defined using css classes, and the django message object has the tags attribute which is based on standard system message codes such as info, error and warning which the documentation suggests that you also use as CSS classes . You might be able to see where this is going. I will return to this when I’ve got it working and can provide a couple of screenshots.

In conclusion, django.messages is a useful addition to Django and, combined with some judicious jQuery-based scripting, creates an attractive method of communicating with your users.

What I have learned today about custom template filters in django

If you make changes to a custom template filter, or, in some cases, even a function that passes data to a custom filter, and the filter stops working, restart your web server. That should reload the filter into the template cache. Takes me a day to realise that usually. Now I’ve written it down I shouldn’t forget. When I can find my glasses. Oh, here they are, on my face.

Dynamic select fields with JQuery and django

I don’t post much about my experiences with django as I’m generally slowly learning and not really coming up with any revelations. However, this week, I’ve come up against a problem that has half an answer, but not a satisfactory one, and one that no-one on the django-users mailing list seems to have been able to resolve.

Your form has nested categories that depend on each other: a top category and a sub category, rather like eBay. Rather than reloading the whole page to get a list of subcategories when a top category is selected, it would look much nicer just to populate the subcategory select field. This is a job for javascript, specifically AJAX, and to save reinventing the wheel, it’s useful to use a library, which in my case is currently JQuery.

This blog post and this blog post set me off in the right direction by showing how to use JQuery’s getJSON function and how to craft custom fields for the lookup.

First, you’ll need to define a form. In this case I’m using a ModelForm with a couple of custom field definitions. This is probably slightly redundant as the field choices will be looked up by the ModelForm factory, but we are changing the definition of the prodsubcat field by disabling its widget, so I’ve also included the field choices for completeness:

class ProductForm(ModelForm):
    prodtopcat = forms.ModelChoiceField(ProductTopCategory.objects, widget=forms.Select)
    prodsubcat = forms.ModelChoiceField(ProductSubCategory.objects, widget=forms.Select(attrs={'disabled': 'true'}))

    class Meta:
        model = Product

Something I bashed my head against for a while was from Dustin’s post: setting the choices option on the widget as follows to display a message in the disabled subcategory field:

prodsubcat = forms.ModelChoiceField(ProductSubCategory.objects, widget=forms.Select(attrs={'disabled': 'true'}), choices=(('-1','Select Make'),))

which looks neat, but wipes out the choices dictionary that is loaded at render time. This is important as it’s that dictionary that the form submission process validates against. I got stuck on that for a day or so.

The javascript to make the JSON request sits in the SCRIPT section in the HEAD part of your template and is pretty simple. It also needs a current version of jQuery to be present:

  $(function(){
    $("select#id_prodtopcat").change(function(){
      $.getJSON("/products/feeds/subcat/"+$(this).val()+"/", function(j) {
        var options = '<option value="">---------- </option>';
        for (var i = 0; i < j.length; i++) {
          options += '<option value="' + parseInt(j[i].pk) + '">' + j[i].fields['longname'] + '</option>';
        }
        $("#id_prodsubcat").html(options);
        $("#id_prodsubcat option:first").attr('selected', 'selected');
        $("#id_prodsubcat").attr('disabled', false);
      })
      $("#id_prodtopcat").attr('selected', 'selected');
    })
  })

This calls a django view that returns a JSON object using HTTP GET. The view looks like this:

def feeds_subcat(request, cat_id):
	from django.core import serializers
	json_subcat = serializers.serialize("json", ProductSubCategory.objects.filter(prodcat = cat_id))
	return HttpResponse(json_subcat, mimetype="application/javascript")

This returns an object filtered on the ProductTopCategory relationship and passes it through the serialiser. The jQuery function(j) formats the JSON object as a HTML SELECT field and writes it to the form using JQuery’s document.write function.

You should now have a form that among other things has an active top category select field and a disabled sub category select field. Selecting an option in the top category field should enable the sub category and populate it with a filtered set of options.

Submit the form, and if you’re using the standard django method of submission and validation, it should pass and you can continue to process the form.

The thing that I got stuck on was the validation aspect: in retrospect it’s fairly obvious that the form will validate against the object that it has in memory, but I got sidetracked for a while in other solutions such as attempting to replace the submitted form data, which can’t be done as request.POST is read only (you could make a copy but that really just adds to the codebase), and also creating custom validation for the field that did a lookup for a record that matched the selected option, thus overriding validation of the rendered field.

It’s still a little bit hacky in that it needs two lookups but on the other hand the alternative is to load a potentially big directory structure into the browser memory in order to filter the choices.

Inline editing with Jquery, Jeditable and django

…and two come along at once

In attempting to keep my current project easy to use and pleasingly contemporary, I decided to get javascripty on the user dashboard by enabling editing in place, like all the best Web 2.x sites *cough*.

Inline editing is where a user can change aspects of a page by clicking on the data to be changed, editing in a form object and sending the changed data back to the server. As I have been using Jquery for most of my UI needs, I looked for a solution that used it and found jeditable, a plugin that does exactly what I want it to do, but doesn’t seem to have been documented for django as yet, so here’s a first crack at making it work.

My user dashboard is pretty straighforward from a django perspective and uses the standard AUTH_PROFILE module. It may have to inherit some additional models shortly but in the spirit of keeping it simple, I use django.contrib.auth and a user profile model called UserProfile.

Jeditable is simple enough in a Jquery kind of way: enclose the data that you want to be edited in a div with a class identifier and specify a URL that will process the edited data in the editable function.The demo code is all PHP, but it’s simple enough to translate that to django:

$(document).ready(function() {
     $('.edit').editable('/users/dashboard/edit/{{ user.username }}/', {
     	style: 'display: inline'
     });
});

My URL pattern is fairly easy to work out from that:

(r'^dashboard/edit/(?P<username>\w+)/$', 'edit_dashboard'),

In order to make it generic as possible, there should be one function for the editable area and one django view. This is the science bit. Jeditable sends a POST request which by default is formed thusly:

id=elements_id&value=user_edited_content

This isn’t explained that well on the Jeditable page in my opinion, but the author is Finnish so we’ll let him off. What it means is that the name of the div class is sent a value pair with ‘id’ and the edited data is sent as ‘value’. This is modifiable but it’s as good a default as any to use.

In keeping with django’s MVC structure, set the div element name (‘id’) to be the same as the associated model field. There’s probably a more dynamic way of doing this, such as defining the div element as the field name from the dictionary created by the view, but creating it by hand will be fine. Each div element therefore looks something like this:

<div class="edit" id="first_name">{{ user_obj.user.first_name }}</div>

Pass the field and its value to the view using request.POST.get():

            field = request.POST.get('id', '')
            value = request.POST.get('value', '')

This is where I got a bit stuck for a while. I have the field and I have the value, how do I pass them to the object to be saved? The answer was found in this post by James Bennett. A model, or object derived from a model has an API that calls all sorts of useful information about your model, and, more to the point can be invoked to modify that information in a generic way. The _meta functions are part of django’s internals, and as a comment in the post points out, might be subject to change, but we don’t need to the _meta functions, as the API call that we’re interested in, __setattr__ is also exposed directly to the model or object, so the field and value can be passed to the database like this:

user_obj.__setattr__(field, value)

and can be saved with a simple save() method. Try it in a shell.

UPDATE: this doesn’t work with the User.first_name and User.last_name fields. They can be accessed using

user_obj.user.__setattr__(field, value)

and saved with user_obj.user.save(). The first_name and last_name field in auth seem to be largely deprecated and so might be better off in UserProfile: it certainly saves a couple of lines of code.

Jeditable expects a response, which a PHP author would roll themselves. Fortunately, django has HttpResponse. I return the value variable, which is displayed as the edited data. The stored data will not be shown until the page is fully reloaded.

This example is pretty primitive really, and there are things that seem to be able to be improved. The database query is a simple user.get_profile() call but this request gets made for every item that is changed, which seems inefficient. It seems there should be something a bit more asynchronous about it , possibly using JSON or XML and making a periodic save rather than a query for every item. A bit of processing power could be saved if we checked if the data had changed before saving it. However, at the moment I’m a programmer with a deadline 😉