Table Of Contents

Previous topic

workflow

This Page

Misc

settings.py and localsettings.py

The settings for your project which are a machine specific should be refactored out of settings.py into localsettings.py. In your settings.py, you should do:

try:
    from localsettings import *
except ImportError:
    print 'localsettings could not be imported'
    pass #Or raise

This should be at the end of settings.py, so that localsetting.py override settings in settings.py

This file should not be checked in your repository.

Use relative path in settings.py

Instead of writing:

TEMPLATE_DIRS = '/home/user/project/templates'

Do:

#settings.py
import os

CURRENT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = os.path.join(CURRENT_DIR, 'template')

Use templatetags when the output doesnot depend on the Request

In your sidebar suppose you want to show the 5 latest comments. You do not need the request to output this. Make it as a templatetag.

Import as if your apps are on your project path

Instead of doing from project.app.models import ModelClass do from app.models import ModelClass. This makes you apps reusable as they are not tied to a project.

Naming things

Model class names should be singular, not plural.:

class Post(models.Model):
    ...

and not:

class Posts(models.Model):
    ...

Foreign key should use the name of the referenced class.:

class Post(models.Model):
        user = models.ForeignKey(User)

Querysets should be plural, instances should be singular.:

posts = Post.objects.all()
posts = Post.objects.filter(...)

post = Post.object.get(pk = 5)
post = Post.object.latest()

Using pdb remotely

Sometimes you will hit bugs which show up on servers but not on your local system. To handle these, you need to debug on the server. Doing manage.py runserver only allows local connections. To allow remote connections, use:

python manage.py runserver 0.0.0.0:8000

So that your pdb.set_trace() which are on remote servers are hit when you access them from your local systems.

Do not use primary keys in urls

If you use PK in urls you are giving away sensitive information, for example, the number of entries in your table. It also makes it trivial to guess other urls.

If possible use Slugs in urls. This has the advantage of being both user and seo friendly.

If slugs do not make sense, instead use a CRC algorithm.:

class Customer(models.Model):
    name = models.CharField(max_length = 100)

    def get_absolute_url(self):
        import zlib
        #Use permalink in real case
        return '/customer/%s/' % zlib.crc32(self.pk)

Prefer ModelForm to Form

ModelForm already know the correct UI widgets for your underlying Models. In most of the cases ModelForm would suffice instead of Forms.

Some common scnarios

Hiding some fields from ModelForm which are needed for a DB save.

Eg, you want too create a profile for the logged in user.:

#in Forms.py
class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude =['user',]

#In Views:
form = ProfileForm(request.POST)
profile = form.save(commit = False)
profile.user = request.user
profile.save()

Or:

#Todo test this
class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude =['user',]
    def __init__(self, user, *args, **kwargs)
        self.user = user
        super(ProfileForm, self).__init__(*args, **kwargs)

    def save(*args, **kwargs):
        self.instance.user = self.user
        super(ProfileForm, self).save(*args, **kwargs)

Saving multiple Objects in one form

As:

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude =['user',]

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        exclude =[...]

#in views.py
userform = UserForm(request.POST)
profileform =  ProfileForm(request.POST)
if userform.is_valid() and profileform.is_valid():
    #Only if both are valid together
    user = userform.save()
    profile = profileform.save(commit = False)
    profile.user = user
    profile.save()

{# In templates #}
<form ...>
{{ userform }}
{{ profileform }}
<input type="submit" />
</form>

Forms should know how to save themselves.

if your forms is a forms.ModelForm, it already knows how to save its data. If you write a forms.Form, it should have a .save(). This keeps things symmetrical with ModelForms, and allows you to do:

#in views.py
def view_func(request):
    if request.method == 'POST':
        form  = FormClass(request.POST)
        if form.is_valid():
            obj = form.save()
            ...
        ...

Instead of:

if form.is_valid():
    #handle the saving in DB inside of views.

The .save() should return a Model Object

Code defensively in middleware and context processors.

Your middleware and context processors are going to be run for all requests. Have you handled all cases?

def process_request(request):
if user.is_authenticated():
profile = request.user.get_profile()#Hah, I create profiles during
#registration so this is safe.

...

Or it is? What about users created via manage.py createsuperuser, with the above middleware, the default user can not even access the admin site.

Hence handle all scenarios in middleware and context processors. This is one place where try: .. except: .. (bare except) blocks are acceptable. You do not want one middleare bringing down the entire site.

blog comments powered by Disqus