Django

Django: Sending mail with Templates

It’s interesting how only a few lines of code can save so much work. A few days ago, I was working on adding a new feature to a system I wrote a while ago using django. I noticed there were a few places that I wanted to send out an email along with logging. I started looking into Django’s ability to send out emails, after much searching I found the mail_admins function. I wasn’t a huge fan of having the email content buried in the code. I did a few quick searches on the documentation and came up with no real solutions. Using Django’s render_to_response as an example I created a function that would allow me to send an email using a Django template.


from django.template import loader
from django.core.mail import mail_admins

def render_to_email(template, subject, context):
    template = loader.render_to_string(template,  context)
    mail_admins(subject, template)

The function works exactly like Django’s render_to_response function, with one added value to the function for setting the email’s subject


render_to_email('email_general_error.html', 'General Error', { 'request': request, 'message': message})

Django ModelForms With Foreign Keys

I have recently been working more and more with django forms. In previous projects we decided not to use them mostly cause we couldn’t get them to do what we wanted them to do. In retrospect it was more of a lack of understanding how they worked and insufficient time to sit down and learn them.

Earlier in the week I was working with a model based form with a foreign key to another model. Problem I ran across was that I wanted said form to be displayed on the page, and also post the proper foreign key id without the user selecting it ( foreign keys are selected through a select box which can get quite large ). The page in which this form would be displayed would always know the foreign key id, so there would never need to be a situation where the form would ever need to show the user a select box.

After much trial and error, here is what I came up with.


from django.forms import ModelForm
from django import forms
from models import Thread
from models import Post

class ThreadForm(ModelForm):
    class Meta:
        model = Thread
        fields = ('Message', 'user')

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ( 'Message', 'user')

The Post in question would normally have a foreign key in this instance to Thread, but we exclude it from the form so that it is not validated against or displayed to the user.


    <form action="/post/{{ thread.pk }}/" method="post">
        {{ form.as_p }}
        <input type="submit" value="Submit" />
    </form>

In the actual form posting we are using the threads key in the url that is receiving the new post, If you were not using in the url, you could simple just add it as a hidden value on the page.


def post_add(request, thread_id):
    a_form = PostForm(request.POST)

    if(a_form.is_valid()):
        post = a_form.save(commit=False)
        post.thread_id = thread_id
        post.save() 

In the post_add view which accepts the thread_id and passes it to the method, we create the form based on the post data. validate it and save it. By adding the commit=False we stop the Form from saving the data to the database. and we return a model object. Which we can then pass along the thread_id and save it.

Their are a few things that could be added to the view for extra checking. We could do a lookup for a thread id and make sure its there, and do checks for request.method, or even add in handling for ajax requests. The example view isn’t complete and is only there as a quick sample of how to handle these types of forms.

Mobile Site Redirection

In recent years a major component for any popular site is to add some sort of mobile experience. By adding a mobile aspect of your site either in full or in part, you open it up to even more people. In the last few years as mobile phones have become more powerful and less money. Having a mobile phone that is capable of viewing a full sized normal webpage isn’t as heard of now as it was just a few years ago.

With phones being capable of viewing sites in full and as mobile markup, it can sometimes be harder to present the user with the experience they are looking for. Simply using the user agent can help but it doesn’t give a full indication if the user has there browser setup as full or mobile. There is another way that can be used to some extent and works on any phone with a properly implemented browser.

HTTP_ACCEPT, is a header that is sent from the browser to the server when requesting resources. Contained in this header is a description of what the browser is capable of accepting or is willing to accept. Using this header it is possible to help determine if the user is on a mobile phone viewing in “mobile mode” or as a full browser. By checking for “application/vnd.wap.xhtml+xml” you can be assured that the user is viewing the site on a “mobile” browser.


from django.http import HttpResponseRedirect
from django.conf import settings

class MobileMiddleware(object):
  def process_request(self, request):
    try:
      if(request.META.get('HTTP_ACCEPT', '').find("application/vnd.wap.xhtml+xml") >= 0):
        return HttpResponseRedirect(settings.MOBILE_SITE)
    except:
      pass
    return None

Setting this up as a middleware in your settings file, as well as adding a new directive in your settings file such as:

Settings.py


MOBILE_SITE = "http://m.domain.com/"

This will allow you to simple redirect users on viewing the site as “mobile” to be redirected to the mobile site. A couple things to keep in mind though. If you are using the same code and just using different templates for the main site and the mobile site, you will want to add in logic to make sure you don’t hit a continous loop. Since not all browers are written to full standard, this isn’t 100%, but nothing is this will just help in giving users a more seamless user experience.

Django Json Woes

Recently I have been working on a new web project, written in Python using the Django web framework. I have been using Django off and on over the last year, traditionally I really never used much of a framework. A great deal of my time prior to Python/Django work was spent on applications development for server side processes written in C#.

I have a strange love/hate relationship with python, I love some of its capabilities, ease of use, and its concise nature. On the other hand I hate that there seems to be some things that I would love to see that just isn’t there. While writing a simple view in which I planned on returning a JSON string back to the user, I found there was no “response” or internal method that I could find to return it simply. In the process of going through the documentation I found some information relating to the HttpResponse that gets returned at the end of each View. I figured that would be a great place to start.


from django.http import HttpResponse
from cjson import encode

class JsonResponse(HttpResponse):
  def __init__(self, data, status = 200):
    HttpResponse.__init__(self, content = encode(data), mimetype = 'application/json', status = status)

First revision looked something like this. At first it worked out doing what I had wanted, one problem I had was while using a mime type of ‘application/json’ was more secure it made debugging a little more difficult when hitting the view directly in the browser. So I figured if I was running in debug why not use a mime type of ‘text/html’, its less secure but debug should never run on production.


from django.http import HttpResponse
from django.conf import settings
from cjson import encode

class JsonResponse(HttpResponse):
  def __init__(self, data, status = 200):
    mimetype = 'application/json'

    if(settings.DEBUG):
      mimetype = 'text/html'

    HttpResponse.__init__(self, content = encode(data), mimetype = mimetype, status = status)

This revision looked much more what I needed. The only problem I had was when hitting this view from Javascript on the client side, some browsers would cache the return value and an additional hit to the view wouldn’t occur. I could have solved this on the client side by adding some sort of random seed to the end of the URL. However I would much prefer my view decide when something needs to be cached rather than the JavaScript code so I made a few modifications.


from django.http import HttpResponse
from django.conf import settings
from cjson import encode

class JsonResponse(HttpResponse):
  def __init__(self, data, status = 200, cache = False):
    mimetype = 'application/json'

    if(settings.DEBUG):
      mimetype = 'text/html'

    HttpResponse.__init__(self, content = encode(data), mimetype = mimetype, status = status)

    if(cache == False):
      self['Last-Modified'] = 'Mon, 01 Jan 1970 05:00:00 GMT'
      self['Cache-Control'] = 'no-store, no-cache, must-revalidate'
      self['Pragma'] = 'no-cache'

Making this change allowed me to have the flexibility of deciding if I wanted something cached, which in most instances I don’t since the data for these returns are normally always changing. With this new object I was able to perform a “standard” JSON return in a view as well as maintain a single place I can make modifications to all requests at once.


from responses import JsonResponse

def json_view(request):
  x = { 'status': True, 'message': 'Success' }
  return JsonResponse(x)