Forked from goldhand/Django + Ajax dynamic forms .py
Created
January 4, 2018 14:15
-
-
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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') | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import forms | |
class TaskForm(forms.ModelForm): | |
class Meta: | |
model = Task |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
class Task(models.Model): | |
title = models.CharField(max_length=255) | |
description = models.TextField() | |
def __unicode__(self): | |
return self.title |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--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> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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