Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save EmadMokhtar/8ddf5764bf282b428fa995c680baf015 to your computer and use it in GitHub Desktop.
Save EmadMokhtar/8ddf5764bf282b428fa995c680baf015 to your computer and use it in GitHub Desktop.
Django form with Ajax. A simple Task model that can be updated using a CBV with an AJAX mixin. The view sends post data with ajax then updates the view with a callback to a DetailView with a json mixin.There is an abstract CBV, AjaxableResponseMixin, based on the example form django docs, that is subclassed in the TaskUpdateView CBV. TaskUpdateV…
#models.py
class Task(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
def __unicode__(self):
return self.title
#views.py
import json
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.views import generic
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponse
from braces.views import JSONResponseMixin # http://django-braces.readthedocs.org/
from .models import Task
from .forms import TaskForm
class AjaxableResponseMixin(object):
""" Ajax form based on the django docs example.
https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-editing/#ajax-example
https://docs.djangoproject.com/en/dev/topics/class-based-views/mixins/#more-than-just-html
"""
def render_to_json_response(self, context, **response_kwargs):
"""Render a json response of the context."""
data = json.dumps(context)
response_kwargs['content_type'] = 'application/json'
return HttpResponse(data, **response_kwargs)
def form_invalid(self, form):
response = super(AjaxableRetosponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return self.render_to_json_response(form.errors, status=400)
return response
def form_valid(self, form):
response = super(AjaxableResponseMixin, self).form_valid(form)
if self.request.is_ajax():
# Request is ajax, send a json response
data = {
'pk': self.object.pk,
}
return self.render_to_json_response(data)
return response # Request isn't ajax, send normal response
class TaskAJAXView(JSONResponseMixin, generic.DetailView):
"""Model view for displaying tasks in JSON."""
model = Task
content_type = 'application/javascript'
json_dumps_kwargs = {'indent': 2}
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context_dict = {
'title': self.object.title,
'description': self.object.description,
}
return self.render_json_response(context_dict)
class TaskUpdateView(AjaxableResponseMixin, generic.UpdateView):
"""Update view that handles both html and ajax updates."""
model = Task
form_class = TaskForm
# forms.py
from django.db import forms
class TaskForm(forms.ModelForm):
class Meta:
model = Task
#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^tasks/update/(?P<pk>\d+)/$', views.TaskUpdateView.as_view(), name='task-update'),
url(r'^tasks/ajax/(?P<pk>\d+)/$', views.TaskAJAXView.as_view(), name='task-ajax-detail')
]
// javascript
// Resources used in this example:
// http://net.tutsplus.com/tutorials/javascript-ajax/submit-a-form-without-page-refresh-using-jquery/
// I put this on the template page so it can be manipulated with context. I wouldn't suggest doing that
function getCookie(name) {
// get the csrf token
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
$(":input").change(function() {
// validate and process form
var title = $("input#id_title").val();
if (title == "") {
$("#div_id_title").addClass('error');
$("input#id_title").after('<span class="help-inline">Title required</span>');
$("input#id_title").focus();
return false;
} else {
$('.help-inline').remove();
$("#div_id_title").removeClass('error');
}
var description = $("textarea#id_description").val();
if (description == "") {
$("div_id_description").addClass('error');
$("textarea#id_description").after('<span class="help-inline">Required</span>');
$("textarea#id_description").focus();
return false;
} else {
$('.help-inline').remove();
$("div_id_description").removeClass('error');
}
var dataString =
'title='+ title
+ '&description=' + description
+ '&csrfmiddlewaretoken=' + getCookie('csrftoken');
$.ajax({
// django mixin
type: "POST",
url: "{% url 'task-update' task.id %}",
data: dataString,
success: function() {
$('#message).html("<ul id=\'message\'></ul>")
.hide()
.fadeIn(1500);
$.getJSON("{% url 'task-ajax-detail' task.id %}",function(result){
$.each(result, function(i, field){
$("#result").append("<li>" + i + " : " + field + "</li>");
});
});
}
});
return false;
});
});
runOnLoad(function(){
$("input#id_title").select().focus();
});
from django.db import forms
class TaskForm(forms.ModelForm):
class Meta:
model = Task
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
def __unicode__(self):
return self.title
<!--task_form.html-->
{% load staticfiles %}
<!--some of these-->
{% block jquery %}<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>{% endblock jquery %}
<script src="{% static 'js/bootstrap-dropdown.js' %}"></script>
<script src="{% static 'js/bootstrap-tab.js' %}"></script>
<script src="{% static 'js/bootstrap-transition.js' %}"></script>
<script src="{% static 'js/bootstrap-alert.js' %}"></script>
<script src="{% static 'js/dynamicForms.js' %}"></script>
<ul id=’message’></ul>
<div id="task_form">
{% form %}
</div>
<div>
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^tasks/update/(?P<pk>\d+)/$', views.TaskUpdateView.as_view(), name='task-update'),
url(r'^tasks/ajax/(?P<pk>\d+)/$', views.TaskAJAXView.as_view(), name='task-ajax-detail')
]
import json
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.views import generic
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponse
from braces.views import JSONResponseMixin # http://django-braces.readthedocs.org/
from .models import Task
from .forms import TaskForm
class AjaxableResponseMixin(object):
""" Ajax form based on the django docs example.
https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-editing/#ajax-example
https://docs.djangoproject.com/en/dev/topics/class-based-views/mixins/#more-than-just-html
"""
def render_to_json_response(self, context, **response_kwargs):
"""Render a json response of the context."""
data = json.dumps(context)
response_kwargs['content_type'] = 'application/json'
return HttpResponse(data, **response_kwargs)
def form_invalid(self, form):
response = super(AjaxableRetosponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return self.render_to_json_response(form.errors, status=400)
return response
def form_valid(self, form):
response = super(AjaxableResponseMixin, self).form_valid(form)
if self.request.is_ajax():
# Request is ajax, send a json response
data = {
'pk': self.object.pk,
}
return self.render_to_json_response(data)
return response # Request isn't ajax, send normal response
class TaskAJAXView(JSONResponseMixin, generic.DetailView):
"""Model view for displaying tasks in JSON."""
model = Task
content_type = 'application/javascript'
json_dumps_kwargs = {'indent': 2}
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context_dict = {
'title': self.object.title,
'description': self.object.description,
}
return self.render_json_response(context_dict)
class TaskUpdateView(AjaxableResponseMixin, generic.UpdateView):
"""Update view that handles both html and ajax updates."""
model = Task
form_class = TaskForm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment