Jul 14, 2014

Virtualenv for Django

One of main features and troubles for Django projects is the Django version you are using. Example for this would be the occasion of starting project for Django 1.4.x version. Trying to run it under Django 1.7.x would lead to various troubles, counting template changes, misconfiguration errors and so on.

Solution is to use virtual environment. The tool for this is called Virtualenv. It is a wrapper for a python interpreter. It enables you to have multiple versions of python packages that run independently.

The Virtualenv creates you a standalone environment. Basically it copies and keeps a system Python of yours in a specified directory. All the python packages will be installed there. (In case you have not forgot to activate it first, of course)

Lets get started then. We need Virtualenv itself for the first. There are many ways to install it depending on your system. Most obvious to use pip. Your installation command will look something like that:
pip install virtualenv
This installs the tool itself to your system. this only must be done once.

Assuming we have it now and going forward to usage basics. We need to create a virtual environment for our particular project. Usual rule for most of developers is to have a single virtual environment for a standalone project.
To create one for ours we need to be in the directory where we want it to reside. (Virtual environment is not movable by default). So choose wisely.
I suggest it be somewhere in the project directory. The directory that is up one step from the project one is ok too. Assuming we have a project that is called "example". I will enter the directory of that project:
$ cd example
garmoncheg:~/Projects/example$ ls -la
total 8
drwxr-xr-x  4 garmoncheg  staff   136B Jul 14 14:26 ./
drwxr-xr-x  3 garmoncheg  staff   102B Jul 14 14:26 ../
drwxr-xr-x  6 garmoncheg  staff   204B Jul 14 14:26 example/
-rw-r--r--  1 garmoncheg  staff   250B Jul 14 14:26 manage.py
We have here a manage.py file to run our project with and a project files directory. Seems like a nice place to create a virtual environment at. Time to do it with executing a command:
$ virtualenv venv
New python executable in venv/bin/python
Installing setuptools............done.
Installing pip...............done.
We have commanded our virtualenv to create a directory for our new project environment and call it venv. You could use any name here. it will indicate your projects name or whatever your fantasy is up to. Mine project directory now looks like this:
$ ls -l
total 9
drwxr-xr-x  6 garmoncheg  staff   204B Jul 14 14:26 example/
-rw-r--r--  1 garmoncheg staff   250B Jul 14 14:26 manage.py
drwxr-xr-x  6 garmoncheg  staff   204B Jul 14 14:32 venv/
I have a mange.py script here, example directory with project files and a venv directory containig my environment files.
Now we have created a directory for environment and put our environment in it. However system is not aware we are using this environment. We must activate it now. Doing that is easy enough.
Assuming you are in the same project directory and called the virtual environment we are creating "venv". Execute a command:
$ source venv/bin/activate
(venv)garmoncheg:~/Projects/example$ 
This will tell the system we are using the interpreter set we have just created. It is indicated with (venv) at the start of your terminal prompt. this means we are "inside" the environment now.
Note we are in the same directory we where before.

Lets familiarise ourselves with main virtualenv functionality now. Whats the main point of it?
Simple. All the "pip install something" made now in this terminal will install a Python package inside this venv folder, leaving the main system python files intact. You can have as many environment as you wish. You can install whatever Python package you want inside of that virtual environment.

Now lets go through basic commands. Lets try to run our project now, assuming you have followed my previous instructions. To do that just type:
(venv)$ ls
total 9
drwxr-xr-x  6 garmoncheg  staff   204B Jul 14 14:26 example/
-rw-r--r--  1 garmoncheg  staff   250B Jul 14 14:26 manage.py
drwxr-xr-x  6 garmoncheg  staff   204B Jul 14 14:32 venv/
(venv)garmoncheg:~/Projects/example$ python manage.py runserver
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ImportError: No module named django.core.management
Whoops. We can not do that because there is no Django installed. Even though you have had it in system it does not seem to be present now.
All the credits to virtualenv activation command. (source path/to/activate/script). We have to have it installed in the environment now. However it is more convenient to look for ourselves there is no Dango in environment. Lets execute:
(venv)garmoncheg:~/Projects/example$ pip freeze
wsgiref==0.1.2
Tadaam. We only have wsgiref in our console environment now. Lets install django:
(venv)garmoncheg:~/Projects/example$ pip install django
Downloading/unpacking django
  Downloading Django-1.6.5.tar.gz (6.6MB): 6.6MB downloaded
  Running setup.py egg_info for package django
    
    warning: no previously-included files matching '__pycache__' found under directory '*'
    warning: no previously-included files matching '*.py[co]' found under directory '*'
Installing collected packages: django
  Running setup.py install for django
    changing mode of build/scripts-2.7/django-admin.py from 644 to 755
    
    warning: no previously-included files matching '__pycache__' found under directory '*'
    warning: no previously-included files matching '*.py[co]' found under directory '*'
    changing mode of /Users/leopard/Developer/Python/Me/Tests/Projects/example/venv/bin/django-admin.py to 755
Successfully installed django
Cleaning up...
Tadaa. We have our django for the project now. Lets make sure with pip freeze:
(venv)garmoncheg:~/Projects/example$ pip freeze
Django==1.6.5
wsgiref==0.1.2
And our project now can run inside a wrapper. Lets test with:
(venv)leopard@garmoncheg:~/Projects/example$ python manage.py runserver

Validating models...

0 errors found
July 14, 2014 - 12:00:03
Django version 1.6.5, using settings 'example.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Yes it works.

Cons here that we must activate a virtual environment each time we want to seriously interact with our project. So even to run it we need to activate it first. but it is really the only option to work with multiple project in a system in an easy way.

To return the terminal to a proper state (back to system Python interpreter) you could just close it or deactivate the environment:
(venv)garmoncheg:~/Projects/example$ deactivate
garmoncheg:~/Projects/example$ 
Tadaa. (venv) preceding the terminal prompt is gone and we are back to the system interpreter.

Hope this helps someone. Suggestions? Helped? Please comment! I will really appreciate all the info.

Jun 12, 2014

Django CMS custom Plugin ManyToMany fields problems.

Developing a website for Django CMS I have done a plugin. This plugin however have had a problem. It had an m2m field. While selecting images there (It was a gallery plugin). It was not saving it to production. This way main problem with this field was that plugin have displayed m2m choices on a draft page and while storing it to live it fails.
Django CMS Pages is built like so it has multiple versions of pages. Each Page model that is changed is stored under new revision. And so plugin is copied and relinked to that page too. So plugin revisions multiply to.
For e.g. in case you have a Draft page with two plugins that have model primary key number (pk in future) 12 and 14 accordingly. Say you hit publish changes. Not only PK of Page model rises and data are copypasted into new empty Page model instance. Those plugins are copied to. So mentioned plugins PK would change to 15 and 16 accordingly, assuming 14 is the latest plugin pk. New copied plugins will be linked to new page. Thats how things work in Django CMS.

There is also a line in the CMS code stating in its comment that you need to override m2m storing by yourself.  Somehow its omitted from basic Django CMS tutorials and I can only find it in the old versions documentation for now. SO THE SOLUTION TO ALL THIS:

Say you have CMSPlugin a model for your custom plugin:
class SelectImagePlugin(CMSPlugin):
    """Extension model for plugin class"""
    display_text = models.BooleanField('Project text overlay display')
    images = models.ManyToManyField(Image)

    def copy_relations(self, old_instance):
        self.images = old_instance.images.all()
Here method copy_relations overrides default empty method.
For foreign keys it is described another behaviour and copy_relations mappings. However Foreign keys were working like intended by themselves in my plugins. SO I believe info about them is outdated a bit.
Otherwise it may be useful to read about it in official docs.
http://django-cms.readthedocs.org/en/latest/extending_cms/custom_plugins.html#handling-relations
Thats it. Hope it will help someone like myself to solve a problem like this in a timely manner.
Comments? Suggestions?

May 9, 2014

Implementing a Multiple (Radio) Select + “Other” widget in Django

I have had a task to implement Radio Select field with "Other" choice field in a Django Model Form. Here is my implementation in case someone would benefit from it. The idea is to have it all stored to Django's CharField type of data and have a preselected set of fields. We have a model:
# models.py
class Entry(models.Model):

    SET_OF_CHOICES = (
        ('choice1', 'choice1'),
        ('choice2', 'choice2'),
        ('choice3', 'choice3'),
        ('Other', 'Other Please Specify'),
    )

    choice = models.CharField(_("Selected your choice"), max_length=250)
That makes it ready for the set of fields for for our form. We are overriding Model form default field for this type of data (CharField) by intentionally specifying field with the same name.
# forms.py
from django.forms import ModelForm, ChoiceField, RadioSelect
from models import Entry
from fields import ChoiceWithOtherField


class EntryForm(ModelForm):

    choice = ChoiceWithOtherField(label=_("Selected your choice"), choices=Entry.SET_OF_CHOICES)
Note the field.py import here. We are using custom form field here. It is a modified version of Django's
MultiValueField.
Here is the fields snippet:
# fields.py
from django import newforms as forms
from django.utils.encoding import force_unicode


class ChoiceWithOtherRenderer(forms.RadioSelect.renderer):
    """RadioFieldRenderer that renders its last choice with a placeholder."""
    def __init__(self, *args, **kwargs):
        super(ChoiceWithOtherRenderer, self).__init__(*args, **kwargs)
        self.choices, self.other = self.choices[:-1], self.choices[-1]

    def __iter__(self):
        for input in super(ChoiceWithOtherRenderer, self).__iter__():
            yield input
        id = '%s_%s' % (self.attrs['id'], self.other[0]) if 'id' in self.attrs else ''
        label_for = ' for="%s"' % id if id else ''
        checked = '' if not force_unicode(self.other[0]) == self.value else 'checked="true" '
        yield '<label%s><input type="radio" id="%s" value="%s" name="%s" %s/> %s</label> %%s' % (
            label_for, id, self.other[0], self.name, checked, self.other[1])


class ChoiceWithOtherWidget(forms.MultiWidget):
    """MultiWidget for use with ChoiceWithOtherField."""
    def __init__(self, choices):
        widgets = [
            forms.RadioSelect(choices=choices, renderer=ChoiceWithOtherRenderer),
            forms.TextInput
        ]
        super(ChoiceWithOtherWidget, self).__init__(widgets)

    def decompress(self, value):
        if not value:
            return [None, None]
        return value

    def format_output(self, rendered_widgets):
        """Format the output by substituting the "other" choice into the first widget."""
        return rendered_widgets[0] % rendered_widgets[1]


class ChoiceWithOtherField(forms.MultiValueField):
    """
    ChoiceField with an option for a user-submitted "other" value.

    The last item in the choices array passed to __init__ is expected to be a choice for "other". This field's
    cleaned data is a tuple consisting of the choice the user made, and the "other" field typed in if the choice
    made was the last one.

    >>> class AgeForm(forms.Form):
    ...     age = ChoiceWithOtherField(choices=[
    ...         (0, '15-29'),
    ...         (1, '30-44'),
    ...         (2, '45-60'),
    ...         (3, 'Other, please specify:')
    ...     ])
    ...
    >>> # rendered as a RadioSelect choice field whose last choice has a text input
    ... print AgeForm()['age']
    <ul>
    <li><label for="id_age_0_0"><input type="radio" id="id_age_0_0" value="0" name="age_0" /> 15-29</label></li>
    <li><label for="id_age_0_1"><input type="radio" id="id_age_0_1" value="1" name="age_0" /> 30-44</label></li>
    <li><label for="id_age_0_2"><input type="radio" id="id_age_0_2" value="2" name="age_0" /> 45-60</label></li>
    <li><label for="id_age_0_3"><input type="radio" id="id_age_0_3" value="3" name="age_0" /> Other, please \\
specify:</label> <input type="text" name="age_1" id="id_age_1" /></li>
    </ul>
    >>> form = AgeForm({'age_0': 2})
    >>> form.is_valid()
    True
    >>> form.cleaned_data
    {'age': (u'2', u'')}
    >>> form = AgeForm({'age_0': 3, 'age_1': 'I am 10 years old'})
    >>> form.is_valid()
    True
    >>> form.cleaned_data
    {'age': (u'3', u'I am 10 years old')}
    >>> form = AgeForm({'age_0': 1, 'age_1': 'This is bogus text which is ignored since I didn\\\\'t pick "other"'})
    >>> form.is_valid()
    True
    >>> form.cleaned_data
    {'age': (u'1', u'')}
    """
    def __init__(self, *args, **kwargs):
        fields = [
            forms.ChoiceField(widget=forms.RadioSelect(renderer=ChoiceWithOtherRenderer), *args, **kwargs),
            forms.CharField(required=False)
        ]
        widget = ChoiceWithOtherWidget(choices=kwargs['choices'])
        kwargs.pop('choices')
        self._was_required = kwargs.pop('required', True)
        kwargs['required'] = False
        super(ChoiceWithOtherField, self).__init__(widget=widget, fields=fields, *args, **kwargs)

    def compress(self, value):
        if self._was_required and not value or value[0] in (None, ''):
            raise forms.ValidationError(self.error_messages['required'])
        if not value:
            return [None, u'']
        # Patch to override model specific other choice and return CharField value instead of choice tuple
        if value[0] == 'Other':
            return value[1]
        else:
            return value[0]
        # Use this for field to return tuple
        #return value[0], value[1] if force_unicode(value[0]) == force_unicode(self.fields[0].choices[-1][0]) else u''
It is based on the code from the snippet by sciyoshi. It is put here because there are some modifications to in inline with idea that things could easily disappear without a trace through the internet.
Anyway it will show something like this in the end:
It's up to your imagination to style it now. Hope this howto helps someone with similar problem to save some time.

May 1, 2014

How to delete a remote git tag

I'm always forgetting this. So decided to put it here for someone's benefit.

I have the git tag added by command:
git tag -a 1.2.0 -m "1.2.0"
this means my tags tree will be updated with the tag 1.2.0 and message 1.2.0
Usually it marks the version of the build/release.

I now push a tag to origin by command:
git push origin --tags
It is possible to see it at my repository github tagged.

Time now to delete a tag.
It can be done by command:
git tag -d 1.2.0
This will remove a local tag 1.2.0. Leaving origin intact. Pushing tags to origin does not give anything.
To remove a remote tag now it is required to execute command:
git push origin :refs/tags/1.2.0
It will remove tag 1.2.0 at origin. This is the only way how to move tags to another commits.

Apr 28, 2014

Pillow compile error clang: -Wno-error=unused-command-line-argument-hard-error-in-future fix


I have had a problem with compiling Pillow recently. the error was with Pillow/Pil compilation.
pillow install error clang: error: unknown argument:
 '-mno-fused-madd' 
[-Wunused-command-line-argument-hard-error-in-future]
Apple updated command line tools. So the cc command was updated too.
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
The bug is in GCC. It is quite serious because those flags support will be dropped in future. Fortunately there is a worakround for now:
export ARCHFLAGS="-Wno-error=unused-command-line-argument-hard-error-in-future"
It works for Pillow 2.4.0 and I can compile it with Apple LLVM 5.1 (That is current now), as of Xcode 5.1.
Hope my findings will help someone.

Feb 3, 2014

Django: adding additional Admin static and writing JS snippets for Django Admin

It often gets that you need it because you invent something that is meant to be displayed for admin. E.g. some nasty form field or something. Here is my recipe to add some additional Django static to your admin.

Rather than writing a widget, that is more proper way here... I was using a widget already (from another package). So I could not use it properly, at least without a ton of overrides and complexity it leads to. SO I've decided to add the JS functionality to override a lack of backend.

First of all we should add the javascript/css like so:
# admin.py
class MyModelAdmin(admin.ModelAdmin):
    # admin additions

    class Media:
        css = {
            "all": ("css/my_style.css",)
        }
        js = ("js/my_script.js",)
This add should list your files, loaded in the admin. So you can access them and see in the Django admin frontend itself. Like so:
Now that your script and style are loaded you could just hack anything you want dynamically. Django admin already has a jQuery attached, so you can do whatever you want with it. But there is a problem. You can not just do $(....... your code. This simply does not work and will get error like this:
(Uncaught TypeError: Property '$' of object [object Object] is not a function)
There is no usual jQuery namespace there. but there is a simple hack.
var $ = django.jQuery;

// your usual jQuery code goes here
// e.g.:
// $(document).ready(function() {
    // $('#admin_big_image').wrap('<div class="mrmen-b">');
// });
Thats all. Yu may improvise. E.g. dynamically create or alter DOM elements and manipulate them. Im my case it was a simple Admin banner overlay into image displayed by 3-d party django plugin.
Imagination is the limit.

External links:
http://stackoverflow.com/questions/4709298/difficulty-with-django-and-jquery-why-is-undefined-in-the-admin-app About what may be wrong with your scripts
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-asset-definitions About whee is this idea taken from in Django docs.

Suggestions? Wrong? Comment here!

Jan 2, 2014

Lightning unofficial cable trick for iOS 7

I have found a hack of how to firs time sync your iphone via unofficial (cheap Chinese) cable.
It may be a hint to you if you are buying an iPhone from a second hand without accessories.

You will need TADAA! Official Apple cable but not for a lightning port. And another Apple device.

The thing is if you connect both your new iPhone or iPad via lightning port and using unofficial cable and ANY of your Apple devices using OFFICIAL Apple cable. It will trust your lightning connected device.

Some magic happens and one device connected with official apple cord makes another device connected via official cord too.

TADAA. Now you can sync at least once... and use Wi-Fi sync later on...

Hopoe it helps you. Comments?

Dec 30, 2013

CentOS Install SSH server and configure for VirtualBox testing

I have had some tasks to configure and install a CentOS distribution for my bug-tracking needs. Hope to help out someone with similar problems and or tasks.

I'll be using a fresh install of a CentOS Minimal 6.5.  And a Mac Book Pro with VirtualBox installed (as my testing environment).

First after install of a clean CentOS you need an SSH server to work in your usual environment. So to connect to a Linux, installed in a VirtualBox you will need basically 2 things:
  • openssh-server install
  • disable firewall
  • VirtualBox Port configuration/Access configuration

OpenSSH server install

To install server you need to run in your VirtualBox Guest system (CentOS VM):
yum -y install openssh-server
And start and add it to auto launch at system startup:
chkconfig sshd on
service sshd start
Also make sure port 22 is opened in your VM. type:
netstat -tulpn | grep :22

Firewall settings

Because it's a VM you can simply disable the firewall. But be sure not to do this at deployment/production server of any kind.

To disable firewall and remove from auto lunch at system startup run:
service iptables stop
chkconfig iptables off

VirtualBOX

To connect your Guest machine to your Host machine (basically up a network between virtual CentOS and your host Mac OS (In my case) you have several options.
I'll stop on a simple one. You may do a Bridged network connection and have your router/whatever assign your VM an IP address inside your network.
You may also select NAT and configure port mappings. But it's fairly more complex rather then this setting and exceeds the scope of this article.

Connect

Now you need to reboot your CentOS or either reboot network inside your VM. As a result, after reboot you should get assigned IP address. You can view it using command:
$ ifconfig
eth0      Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX  
          inet addr:192.168.1.104  Bcast:192.168.1.255  Mask:255.255.255.0
Mine got an IP ending with 104.
And so now you can ssh connect to your VM terminal using something like:
$ ssh root@192.168.1.104
root@192.168.1.104's password: 
Last login: ...
[root@localhost ~]# 
Tadaa! Your system is up and ready for experiments. Just be sure to save your state with VM snapshots ;)

Comments?

Dec 13, 2013

Python Generators explained simply.

I'm often confused by recent obsession of generators in python. I'll try to explain them as simply as possible. Say you have never used iterators but coded in python. BUT I'm sure you have used dictionaries (dict) and have met requirement to iterate through it's keys and/or values. TADA! You have used generators already ;).

So generator is a function in python. Except for it uses a keyword yield in it's code. Thus making it the iterator. So you could call this function in a sequence like you would probably do iterating over a dictionary already. E.g.:
# typical iteration through dictionary key: value set
for key, value in dict.iteritems():
   # do someth

# Usage of your own iterator
for item in iterator_functuon():
   # do something with function generated output
So this function returns an iterator generator like the dict() type has by default. And has a next() function, like usual iterators have.
So in attempt to using human language:
Generators are simple functions converted to iterators.
So when a generator function calls it's magic word yield, the "state" of the generator function is frozen; the values of all variables are saved and the next line of code to be executed is recorded until next() is called again. Once it is, the generator function simply resumes where it left off. If next() is never called again, the state recorded during the yield call is (eventually) discarded.
So. that was the theory. Better to look at example well commented out:
def gen_odd_nums():
 # executed once (first call) usually like __init__() of a generator
    odd_num = 1
    while True:
     # saves context and return from function
        yield odd_num
        odd_num = odd_num + 2

# Typical generator usage
generator_object = gen_odd_nums()  # initialising a generator once
for i in range(5):
 # calls generator_object.__next__()
    print next(generator_object)
Output will be like:
1
3
5
7
9
That's probably all the magic about the generators. Best way to get it is to open your console. NOW! And try to do it yourself.

Comments?

Nov 29, 2013

AJAX form in Django with jQuery.form plugin

Here I will describe an example form using jQuery Form plugin. It will provide a good frontend, while Django serving a simple backend.
I made this AJAX form using unobtrusive javascript. With human language it means the form will function with JavaScript disabled. And so jQuery.form plugin will work as an AJAX speedup addition and not as a major requirement.

Features:
* Works both with JavaScript  and without.
* Uses standard Django ideology/hooks.
* Uses the most known jQuery plugin for forms AJAX handling.

Theory:
Main idea that Django supports both normal and AJAX request in a standard view. And has a handy request.is_ajax() request method. It returns True/False depending on if request search has HTTP_X_REQUESTED_WITH header for the string 'XMLHttpRequest'. jQuery.form plugin sure does have that.

Backend Django.
We will create an app called 'contact' for our task and place it in the example django project. Urls from the project will redirect to this app. OK. Here is what in our:
urls.py
from django.conf.urls import patterns, url

urlpatterns = patterns('contact.views',
    url(r'^$', 'contact_form', name="contact_form"),
)
Here ve have only one view serving all the needs. and looking at the root of the app. Enough to prove the idea.

forms.py
from django import forms


class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField(max_length=100)
    message = forms.CharField(widget=forms.Textarea(), max_length=1000)
The form is far too simple. But quite sufficient for the concept proof.

views.py
import json

from django.shortcuts import render
from django.http import HttpResponseBadRequest
from django.http import HttpResponse
from django.core.mail import mail_admins
from forms import ContactForm


def contact_form(request):
    if request.POST:
        form = ContactForm(request.POST)
        if form.is_valid():
            # Imaginable form purpose. Post to admins.
            message = """From: %s <%s>\r\nMessage:\r\n%s\r\n""" % (
                form.cleaned_data['name'],
                form.cleaned_data['email'],
                form.cleaned_data['message']
            )
            mail_admins('Contact form', message)

            # Only executed with jQuery form request
            if request.is_ajax():
                return HttpResponse('OK')
            else:
                # render() a form with data (No AJAX)
                # redirect to results ok, or similar may go here 
                pass
        else:
            if request.is_ajax():
                # Prepare JSON for parsing
                errors_dict = {}
                if form.errors:
                    for error in form.errors:
                        e = form.errors[error]
                        errors_dict[error] = unicode(e)

                return HttpResponseBadRequest(json.dumps(errors_dict))
            else:
                # render() form with errors (No AJAX)
                pass
    else:
        form = ContactForm()

    return render(request, 'contact/form.html', {'form':form})
Here we will stop in more detail. We will work out all form possible conditions. e.g. valid/invalid and ajax/plain.
The main form purpose is to actually send a email to admins about contact request for our imaginable site (mail_admins() command and message being created from submitted data).
We have 2 form view conditions here. GET (When we load start of this page) and POST (When we upload the data and parse the form).
In case this view would not have the AJAX part it will look like so:
def contact_form(request):
    if request.POST:
        form = ContactForm(request.POST)
        if form.is_valid():
            # Imaginable form purpose. Post to admins.
            message = """From: %s <%s>\r\nMessage:\r\n%s\r\n""" % (
                form.cleaned_data['name'],
                form.cleaned_data['email'],
                form.cleaned_data['message']
            )
            mail_admins('Contact form', message)
    else:
        form = ContactForm()

    return render(request, 'contact/form.html', {'form':form})
This view works normally with provided template and disabled JavaScript scripts in the template (you may compare it to the first view with AJAX additions). I have not used common possibilities, because I do not need them for demo. It's up to you to decide where to make redirect or so.
Note we are using here request.is_ajax() method and adding another dynamic web page functionality, thus making view behave right for our AJAX needs. And the logic goes into another direction when commented (No AJAX).  Here is where our logic changes go when we do not use jQuery form for request.
Errors here are treated specially. We need the field names of them and the error html to modify for4m in the frontend JavaScript.
Now I hope you understood what is made here. Now let's move on to the templates.
<!DOCTYPE html>
<head>
    <title>Contact</title>
    <script type="text/javascript"
        src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js">
    </script>
    <script type="text/javascript"
        src="http://malsup.github.com/min/jquery.form.min.js">
    </script>
    <script type="text/javascript">
        $(document).ready(function() {
            function block_form() {
                $("#loading").show();
                $('textarea').attr('disabled', 'disabled');
                $('input').attr('disabled', 'disabled');
            }

            function unblock_form() {
                $('#loading').hide();
                $('textarea').removeAttr('disabled');
                $('input').removeAttr('disabled');
                $('.errorlist').remove();
            }

            // prepare Options Object for plugin
            var options = {
                beforeSubmit: function(form, options) {
                    // return false to cancel submit
                    block_form();
                },
                success: function() {
                    unblock_form();
                    $("#form_ajax").show();
                    setTimeout(function() {
                        $("#form_ajax").hide();
                    }, 5000);
                },
                error:  function(resp) {
                    unblock_form();
                    $("#form_ajax_error").show();
                    // render errors in form fields
                    var errors = JSON.parse(resp.responseText);
                    for (error in errors) {
                        var id = '#id_' + error;
                        $(id).parent('p').prepend(errors[error]);
                    }
                    setTimeout(function() {
                        $("#form_ajax_error").hide();
                    }, 5000);
                }
            };

            $('#ajaxform').ajaxForm(options);
        });
    </script>
    <style>
        #form_ajax_error, .errorlist {
            color: red;
        }
    </style>
</head>
<body>
    <h1>Contact</h1>
    <form id="ajaxform" action="{% url contact_form %}" method="post">
        {% csrf_token %}
        {{ form.non_field_errors }}
        {{ form.as_p }}
        <div id="loading" style="display:none;">
            <span id="load_text">loading...</span>
        </div>
        <div id="form_ajax" style="display:none;">
            <span>Form submit successfully.</span>
        </div>
        <div id="form_ajax_error" style="display:none;">
            <span>Can not submit data due to errors.</span>
        </div>
        <p id="sendwrapper"><input type="submit" value="Send" id="sendbutton"/></p>
    </form>
</body>
</html>
Here I have all the script encoded for show purposes. However it is a bad practice. You should not do it in a real life project.
Here we render the form with default django tags and add 3 conditional form help text messages.
They will display and lightly fade after 5 seconds. Saying either script have submitted/loading/errors returned state.
They are controlled with the jQuery script. We also disabling the entire form with all the elements while AJAX is working. SO user can not change the data accidently.
The plugin itself is binded to the form with jQuery command $('#ajaxform').ajaxForm(options). It uses options object created earlier. Here we have 3 condition handlers, as functions. We are locking the form and displaying the loading text (beforeSubmit), submit succeeded (success) and the most interesting one is error handling function (error). It parses JSON provided by the backend in case of errors. Then modifying the DOM with provided errors, relying on the django form rendering logic to find the "id" of the HTML input that needs an error prepended.
Our form will look like so:

I have collected everything in a git repository. You can clone/copy and run it for yourself. The app has some hooks for debug to slow down request/response. So you will be able to see loading state, etc...
Repository with working copy from this app is here:
https://github.com/garmoncheg/ajax_form_example

Comments? Suggestions?