Archive for the 'django' Category

A big win for Django

I know it’s probably been covered before, but check out the license for the :

App Engine Django license

This is fantastic news for the team!

S3 demo using Django

I have been amazed at how reliable storage is these days with services like . The S3 doesn’t mention using python and django so I thought I’d implement the demo in django. It really is very simple to take advantage of S3 in your django apps, as Adrian shows .

Grab the S3 libary from .

My view looks like this:

BUCKET_NAME = 's3demo'

def upload_and_view(request):
    conn = S3.AWSAuthConnection('your access key', 'your secret key')

    if request.method == 'POST':
        post_data = request.POST.copy()
        post_data.update(request.FILES)
        filedata = post_data['uploaded_file']['content']
        filename = post_data['uploaded_file']['filename']
        content_type = mimetypes.guess_type(filename)[0]
        if not content_type:
            content_type = 'text/plain'

        conn.put(BUCKET_NAME, filename, S3.S3Object(filedata),
                    {'x-amz-acl': 'public-read', 'Content-Type': content_type})

    bucket = conn.list_bucket(BUCKET_NAME)
    bucket_entries = bucket.entries

    return render_to_response('s3demo/upload_and_view.html', {'entries': bucket_entries})

The template is a simple web form. bucket_entries contains a list of files in the S3 bucket. Since I’ve set the ACL to be public readable I can print a list of urls like so:

{% for entry in entries %}
<a href="http://s3demo.s3.amazonaws.com/{{ entry.key }}">{{ entry.key }}</a><br />
{% endfor %}

Great stuff!

Newforms widget attributes

The on the django newforms library is rather incomplete at the moment. Any functionality outside of the documentation has to be gleaned from the , the , and google.

I got frustrated that every CharField form element would be rendered on the page with exactly the same size, regardless of what max_length I gave them. I didn’t want to have to render each element by hand, so I looked for and found what I was after. Every newforms widget can be “instantiated” (is instantiated even a concept in python?) with a dictionary of attributes which map to html attributes when rendered.

So for a CharField, I would create my forms subclass like so:

from django import newforms as forms
from django.newforms import widgets

class TestForm(forms.Form):
    subject = forms.CharField(label="Subject",
                                        max_length=45,
                                        widget=widgets.TextInput({'size': 45, 'bogus': 500}),
                                        required=True)

Rendering this form gives the following output:

<input bogus="500" name="subject" maxlength="45" type="text" id="id_subject" size="45" />

Note the “bogus” attribute. This was to test whether django would simply render any attribute in the dictionary, regardless of validity.

Django AMF service

I made a in Jaiku a few days ago that said the following,

Django amf service, once installed is a beauty to behold

Well the key part for me was “once installed”. I’ll attempt to explain how I got it working here.

is a middleware service for Django that allows you create AMF web services. Action Message Format is the web services format typically used by Flex applications by using the . Being able to support remoting web services in Django goes a long way to being able to integrate Flex applications with Django.

Download Django AMF from and install to your site-packages using setup.py. Then add ‘amf.django.middleware.AMFMiddleware’ to the MIDDLEWARE_CLASSES list in your settings. The key thing now is that you need to add the following to your settings,

AMF_GATEWAY_PATH = '/gateway/'
AMF_LOG_LEVEL = 'DEBUG'
AMF_LOG_FILE = 'log/amf.txt'
AMF_LOG_FILE_ENCODING = 'utf8'
AMF_LOG_FILE_MODE = 'a'

AMF_GATEWAY_PATH tells django that anything accessed under this path is an AMF service and gets passed into the middleware. e.g. my urls.py contains

(r'^/gateway/flashtest/test', 'my_app.views.flashtest'),

and that’s it!

I’m using the in Flex to talk to this service as follows:

var service:RemoteService = new RemoteService();
service.gatewayUrl = "http://localhost:8000/gateway/"
service.destination = "flashtest"
service.useAMF0=false
var token:AsyncToken = service.test(test_variable1, test_variable2);

Note that I’ve left the result handlers and assignment of the variables out for brevity, but hopefully you get the picture. The function flashtest gets called and the Flex data types get mapped to python data types as described .

It’s simplicity in design really is beautiful to behold.

A phone type ’sniffer’?

This about an interesting service called on CrunchGear contains the following quote:

By adding a “sniffer” that determines which phone a person accessing the survey is using, the server can feed pages to the user that are optimized for their phone’s particular browser, in WAP, HTML, WHML, or whatever else will be the fastest and most reliable method. This means that one of the biggest hurdles of mobile Web browsing, compatibility, is no longer in the equation.

Is it really that hard to determine which phone type is accessing an HTTP server? No. The phone type is contained in the user agent header that each WAP browser sends in the HTTP request.

Here’s how to capture the user agent in . request.META is a dictionary of all available HTTP headers. The request object is available in any view. Here’s a simple example:

def get_user_agent(request):
    user_agent = request.META['HTTP_USER_AGENT']
    return HttpResponse("Your user agent is: %s" % user_agent)

If I access this view using my Nokia N73 I get the following:

Your user agent is: NokiaN73-1/2.0 (2.0628.0.0.1) S60/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.1

The interesting thing is what you then do with this to determine device capabilities and subsequently serve the appropriate content.

Django version issues on upgrade to 0.96

Seeing as that there will be coming in future releases of Django I installed 0.96 in my environment today. I simply ran setup.py and the libraries were put in the appropriate site-packages directory. The new version seemed to get picked up:

>>> import django
>>> django.VERSION
(0, 96, None)

The mention an additional view for adding users in admin. It didn’t seem to exist for me. It seemed like the old 0.95.1 library I was using was being picked up in this instance, so I removed the egg package for it and all seemed well.

It turns out that the problem was that the older 0.95.x packages used where the new one doesn’t. The new install didn’t create an egg package and the reference to the old one still existed in the easy-install.pth file in my site-packages:

$ cat easy-install.pth
import sys; sys.__plen = len(sys.path)
./setuptools-0.6c5-py2.5.egg
./Django-0.95.1-py2.5.egg
./vobject-0.4.8-py2.5.egg
./python_dateutil-1.1-py2.5.egg
./flup-0.5-py2.5.egg
./MySQL_python-1.2.2-py2.5-macosx-10.3-i386.egg
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,’__egginsert’,0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

Simply removing the reference to Django-0.95.1-py2.5.egg will also do the trick.

Accessing django permissions inside templates

built in permissions system is another piece of excellent functionality you get for free when you use the framework. Each “model” (database table) automatically gets create, delete and change permissions that you can assign to django users and groups. You can create custom permissions per model. Users inside groups inherit permissions assigned to groups. More on that .

Not only views but templates have access to the currently logged in user’s permissions, but it’s not entirely obvious how to get there. You need to pass a RequestContext object to the template first. Here’s how you do it.

from django.template import RequestContext
return render_to_response("mytemplate.html", context_instance=RequestContext(request))

It seems I wasn’t the only one to read the documentation and still not have the objects working in my templates. I searched the django users group and found the posted the same day I started looking at it. A comment in the documentation pointed me to the fact that you need to explicitly pass the object to the template in the render_to_response.

I suppose this highlights the value of using a comments system in documentation, with being one of the best examples I’ve seen of this.

Django and database neutrality

I use the framework on a day to day basis in my job and absolutely love it, especially the database model. The idea is that you generate a “model” for your database and use it using a common API, no matter the backend you’re using. Key supported databases are MySQL, PostgreSQL and sqlite. This works well for the most part.

One key area where it doesn’t is due to the fact that sqlite stores data no matter how it looks. Problems can arise, for example, if you expect a datetime field to be a python datetime object when you pull it out. Believe it or not, this may not always be the case with sqlite.

Another relates to the schema evolution branch that was a google summer of code project. I had an sqlite database that I wanted to update to my latest model, so I thought I’d check out the . With my model updated, I pointed my settings to the old sqlite file and ran manage.py sqlevolve and immediately got the following exception:

File "/path/to/django/core/management.py", line 583, in get_sql_evolution_check_for_changed_field_flags
if column_flags['allow_null']!=f.null or \
KeyError: 'allow_null'

from the function I see the :

column_flags = introspection.get_known_column_flags(cursor, db_table, cf)

Looking at the introspection library for sqlite I see:

def get_known_column_flags( cursor, table_name, column_name ):
    cursor.execute("PRAGMA table_info(%s)" % quote_name(table_name))
    dict = {}
    for row in cursor.fetchall():
        if row[1] == column_name:

            # maxlength check goes here
            if row[2][0:7]=='varchar':
                dict['maxlength'] = row[2][8:len(row[2])-1]

            # default flag check goes here
            #if row[2]=='YES': dict['allow_null'] = True
            #else: dict['allow_null'] = False

            # primary/foreign/unique key flag check goes here
            #if row[3]=='PRI': dict['primary_key'] = True
            #else: dict['primary_key'] = False
            #if row[3]=='FOR': dict['foreign_key'] = True
            #else: dict['foreign_key'] = False
            #if row[3]=='UNI': dict['unique'] = True
            #else: dict['unique'] = False

            # default value check goes here
            # if row[4]=='NULL': dict['default'] = None
            # else: dict['default'] = row[4]
            #dict['default'] = row[4]

    print table_name, column_name, dict
    return dict

Note the commented out code! This, along with the introspection code:

    for row in cursor.fetchall():
        if row[0] == column_name:

            # maxlength check goes here
            if row[1][0:17]=='character varying':
                dict['maxlength'] = row[1][18:len(row[1])-1]

            # null flag check goes here
            dict['allow_null'] = not row[3]

where the dictionary value in question may or may not get assigned.

Looks like django isn’t quite as database neutral as I’d hoped.


Spam Blocked

44,690 spam comments
blocked by
Akismet