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?

Nov 9, 2013

CouchDB restoring deleted/updated documents and their data

We are using CouchDB for production and happy with it. It is much more lightweight rather then MongoDB yet powerful. (For our needs at least). But sometimes you have situations that some code deleted/spoiled your Couch Database data. We had some bugs leading to deleting indexes. However compaction have not been run and here is the decision.

There are several ways for different situations. I'll try to cover them all.
So for deleted CouchDB documents you need to:

1. Make sure your document with this id is Deleted.

To do it you need to request CouchDB for this document. E.g. with this string:
$db/$id
Where $db is your CouchDB database name and $id is your deleted document id
it should return something like this:
{"error":"not_found","reason":"deleted"}

2. Get all the revisions of the deleted document.

With this request:
$db/$id?revs=true&open_revs=all 
Where $db is your CouchDB database name and $id is your deleted document id.

3. Parse response.

CouchDb provides a response with revisions in a special coded format. So to parse this JSON response you need to know it's syntax. It's fairly simple.
 Content - Type: application / json

 {
    "_id": "my-couchdb-id",
    "_rev": "6-65624dd5962e59ff09c47ba1be4f726c",
    "_deleted": true,
    "_revisions": {
        "start": 6,
        "ids": ["65624dd5962e59ff09c47ba1be4f726c", "826046dbd125b841e0dba657f65bbb78", "d1485b8d5cccc305f1dbccf65a07199d", "e1293576c567836c80cd973f36d345aa", "2bbc0c49496d3044c80b824be7e30193", "0aa0c2ce9796de25733b0cf46ee15129"]
    }
}
You can get multiple JSON's like I did. Because document was deleted and undeleted several times.
Anyway. here we have a JSON indicating current (last before deletion) revision of the document. ("_rev": "6-65624dd5962e59ff09c47ba1be4f726c",  ) Let's try to recover it.

4. Find out required revision hash.

Note "_revisions" key in later JSON, containing a list of "ids". Note first one has the same revision hash as the last revision. Our target is previous revision (before deletion). E.g. Or latest one if the document we are trying to recover was just updated, but not deleted. We might need next revision code.
SO in our example:
 "ids": ["65624dd5962e59ff09c47ba1be4f726c",
First one is equal to current and the next one is before it.
Note also key start ("start": 6, ). It indicates latest revision counter. You could stick to that. E.g. subtract 1 from latest revision and add it to the second hash with "-". So to recover previous revision you would need to create a code like this: "5-826046dbd125b841e0dba657f65bbb78". Hope you have understood about how have I come to this.

5. Retrieve previous revision.

To do that just ask couch with address:
$db/$id?rev=$previous_revision
Where $db and $id are your previous database name and deleted code, but $previous_revision is obviously your constructed revision counter + revision hash separated by the "-" symbol. 5-826046dbd125b841e0dba657f65bbb78 In our case.
We will get JSOn of a previous document (before deletion). And we may put it back with PUT/POST request.

It's also worth to mention about when you do not know what revision and/or document $id you want to recover. And want to just recover e.g. previous 10 deleted documents. Then you need to look at request:
$db/_changes
It will provide a list of documents manipulations in the database. It's simple enough. But behind the scope of this article.

That's basically it. Questions/comments?

Nov 6, 2013

OS X Mavericks and Last.FM scrobling of iTunes radio


I have used iTunes radio dramatically after installing a new version of iTunes. But the problem is my musical taste is recorded (Historically) at Last.FM profile. So It is something like combining your Last.FM profile with your iTunes Geniuos data. AFAIK iTunes uses it's data to play songs in a given station. After trying several decisions I have found a nice one that simply works.

You need an app called Bowtie. It's built for older OS X'es. But works nicely for this purpose. It has a themed desktop applet. So it's something like a nice bonus. Anyway you can connect it with Last.FM and that's it. Just one thing it sits in your memory. But I have found it does not consume too much resources or has obvious flaws that spoil Mac anyway.
One trick to install it you need to enable it install your system. It is not from apple store so...
as per stackoverflow question it can be done like so:

Go to System Preferences... > Security & Privacy and there should be a button saying Open Anyway, under the General tab.
Original answer at stackoverflow.com

So that's basically it. Enjoy.