Yay, I contributed a little bit to Django. Exciting to play a teeny tiny part in a really well designed web framework :).

Most of the data in your webapp will be associated with a user (for e.g., I’m the author of this post). django.contrib.auth comes with the User model that handles a lot of basic functionality for dealing with users. Here’s some basic reading.

Some people like to subclass User to add their own pieces of data, others prefer to create a separate UserProfile model. This post assumes that you already know how you’re going to deal with user profiles. What I’ll be talking about is associating models with a specific users. Given that:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField(null=True, blank=True)

I wanted a generic way to add a user to any model. I didn’t want to add a user as a foreign key to Post, and then come back later and have to add it to the comment model as well (if the requirement came up). I wanted a generic way to attach a user to whichever model I wanted. There’ll be other ways to do this (and feel free to point them out), but I went with this:

from django.db import models
from django.contrib.auth.models import User

class UserData(models.Model):
    user = models.ForeignKey(User, editable=False)
    class Meta:
        abstract = True

class Post(UserData):
    title =  models.CharField(max_length=100)
    body =  models.TextField(null=True, blank=True)

Anything that inherits from UserData will have the user field in it. I’ve kept editable=False so that the user doesn’t appear in any forms. However, by keeping editable=False, if you use a PostForm to create/edit, you’ll have to set the user field manually (because user is a required field) in your view like so:


post_form = PostForm(request.POST)

temp_post = post_form.save(commit=False)
temp_post.user = request.user
temp_post.save()

Another variation would be to create a UserDataForm and then inherit your PostForm from it:

class UserDataForm(models.ModelForm):
                        
    # Overriding save allows us to add the user from the request    
    def save(self, user, commit=True):
        # get the instance so we can add the user to it.
        instance = super(UserDataForm, self).save(commit=False)
        instance.user = user

        # Do we need to save all changes now?
        if commit:
            instance.save()
            self.save_m2m()

        return instance

class PostForm(UserDataForm):
    class Meta:
        model = Post

# in your view
def save_post(request):
     post_form = PostForm(request.POST)
     post_form.save(user=request.user)

Interested in hearing how others deal with the same issue.

I’ve been doing a lot Django reading recently (the docs, tutorials, the book, etc) for my current job (not launched yet). I’ve had to dive into the code a few times and it’s been a really fun ride. To help others “get up and running” as soon as possible, I thought I’d post some of the interesting tidbits I learnt from the django book. Ofcourse, you’ll learn more by reading the book yourself and diving into the source code head on.

Here are some cool tricks from the first few chapters, with more coming in the next few days:

  1. Instead of printing values of variables to help with debugging, just put “assert False” in your view and you’ll drop to the error page where you can view all your current variables.

    Ofcourse, if you have ipython installed (and there is no reason you shouldn’t, google it now if you don’t know about it), you can put the following in your view at the top:

    
    from IPython.Shell import IPShellEmbed
    ipython = IPShellEmbed()
    
     

    Now, whenever you put ipython() in your view, you’ll drop into an ipython shell as soon as django’s server hits that view.

  2. By default whenever you do the following in a template

    {{ some_model.some_method_or_attr }}
    

    django will do a dictionary, attribute, method or list index lookup (in that order). You really don’t want to end up in a situation where “some_method_or_var” is a method that can destructively affect your model. There’s a simple way to fix this:

    
    def some_destructive_method(self):
        pass
    
    some_destructive_method.alters_data = True
    
    

    Now, the template system will never execute the method call from the template (it’ll fail silently).

  3. Think its annoying to declare variables in your view and then pass them all one by one to your template like so:

    def my_view(request):
        var1= .. do something
        var2= .. do something
        varn= .. do something
        return render_to_response("template.html", {
            'var1':var1,'var2':var2..,'varn':varn
        }, context_instance=RequestContext(request))
    

    instead, you can use the locals() function (which returns a dict of all local variables for you to conveniently pass it all to the template. Not very pythonic (be explicit), and I personally would prefer never to use it, but a nice shortcut.

  4. You can do {{ block.super }} within a block in a template to get the rendered content of the parent template. A simplistic use-case of this would be using it for the title of the page:

    # base.html
    {% block title %} My cool site {% endblock title %}
    
    # child.html
    {% extends "base.html" %}
    {% block title %} {{ block.super }} : The child page {% endblock title %}
    
  5. Always find yourself getting data from your model and sorting it by a certain field? Put the default sort field in your model like so:

    class News:
        class Meta:
            ordering=['date_updated']
    
  6. You can use index slicing on QuerySet objects too (which translate to sql LIMIT statements). So, get your last 10 posts by:

    Posts.objects.all()[0:10]
    

These are some of the simpler/easier tricks. Some of the more complex stuff’ll be up next..

“hello, world”

Hey, this blogging thing is fun. Now I can be on the internetz.

And hey, people tell me that blogging looks good on the resume too… 😉

blogging-comic-20