Thursday, October 3, 2013

A small example of Django's elegance

Python is an interactive language, thanks to its REPL. And since it's free from typing constraints that weigh down languages like Java, you're free to design an API that is as flexible and easy to understand as you desire.

Want to introspect a field on your Django model? Easy!! Say you have a Foo model and a bar field you want to get.

Something like this:

class Foo(Model):
    bar = CharField(max_length=25)

Let's try and access that bar field!

>>> Foo.bar
AttributeError: type object 'Foo' has no attribute 'bar'

Hm! Well... Huh. Look at that. Take two?

>>> Foo._meta.get_field_by_name('bar')
(<django.db.models.fields.CharField: bar>, None, True, False)

...Right, of course. The old "None, True, False" flags.

>>> Foo._meta.get_field_by_name('bar')[0]
<django.db.models.fields.CharField: bar>

There's that famous Python elegance. That's why they call it executable psuedocode, folks. What do those flags even do? Django's got documentation of famous quality, so let's see what those extra values mean!

https://docs.djangoproject.com/search/?q=_meta&release=7

Hm. Well. Well it's not documented. But they do use it in examples in their documentation. Hm. Well there is that good ol' REPL.

>>> help(Foo._meta.get_field_by_name)
get_field_by_name(self, name) method of django.db.models.options.Options instance
    Returns the (field_object, model, direct, m2m), where field_object is
    the Field instance for the given name, model is the model containing
    this field (None for local fields), direct is True if the field exists
    on this model, and m2m is True for many-to-many relations. When
    'direct' is False, 'field_object' is the corresponding RelatedObject
    for this field (since the field doesn't have an instance associated
    with it).
    
    Uses a cache internally, so after the first access, this is very fast.

Ah of course. That explains it all. That's what I like about Python. Clear, simple, and easy to use. Of course you find those exact same values all across their community, like in Kenneth Reitz's requests library. Or Django. Right?

Monday, January 14, 2013

Django projects at a glance

I have decided to write this after experiencing an extreme amount of frustration at the Django web application framework for Python. Some things are simply not clearly spelled out in the docs.

Django project structure: When possible, make any model a separate app

Any Django project should be a collection of apps. Now, if you're a normal human, you may think of "Chrome" as an app, and maybe "iTunes" and "Microsoft Word" and things like that. However, in Django, app is something on a much smaller scale. If you have blog posts and comments, that's a whole app. That app is separate from a blog authors app. Essentially, you want to break a single web project into as many small apps as you can, even if the apps that make up your site are co-dependent and not usable on their own.

One of the largest benefits to splitting your project into as many apps as possible is it keeps the models.py files a sane size. There is simply no straightforward, supported way to break up models.py. I tried to create a models/ directory with an __init__.py that had `from x import *` for each model module x in my project. This unfortunately lead to my Django fixtures breaking, and as a consequence, half of my tests failing.

Templates and static files go in the app directory

This will help keep all your static files logically separated. Single-use Javascript widgets will get to go in the folder closer to their actual use, while broadly used files go into a central location.

Given your Django app is called 'app': Templates go into app/templates/app. Static files go into app/static/app. The reason you make a new app folder in templates/ and static/ is that Django doesn't split up different app files into different namespaces in any way. Maybe (hopefully) this will be added in a future version of Django, but for now, you must create a root folder for you static files and templates to prevent filename collision with other apps.

As for those global-use files: an ideal central location is not yet known to me. I am still in the process of restructuring my Django project. However, I have a hunch that I'd put project-global files in the the static/ and templates/ directory in the main app (the app with settings.py). I have not yet attempted yet.

More details

For more detail, go to this StackOverflow question. I stumbled upon it just now when trying to figure out