如何将Ajax与Django应用程序集成?

我是Django的新手,Ajax的新手。我正在做一个项目,需要把两者结合起来。我相信我理解它们背后的原理,但还没有找到一个很好的解释两者结合。

有人能给我一个快速的解释,当它们两个集成在一起时,代码库必须如何改变?

例如,我仍然可以使用Ajax的HttpResponse,或者我的响应必须随着Ajax的使用而改变吗?如果是这样,您能否举例说明对请求的响应必须如何改变?如果它有任何不同,我返回的数据是JSON。

120461 次浏览

尽管这并不完全符合SO的精神,但我喜欢这个问题,因为我刚开始的时候也遇到了同样的麻烦,所以我会给你一个快速的指导。很明显,你不理解它们背后的原则(不要把它视为一种冒犯,但如果你知道,你就不会问了)。

Django是服务器端。这意味着,假设客户端访问一个URL,你在views中有一个函数,它呈现他所看到的内容并以HTML形式返回响应。让我们把它分解成例子:

views.py:

def hello(request):
return HttpResponse('Hello World!')


def home(request):
return render_to_response('index.html', {'variable': 'world'})

index . html:

<h1>Hello \{\{ variable }}, welcome to my awesome site</h1>

urls . py:

url(r'^hello/', 'myapp.views.hello'),
url(r'^home/', 'myapp.views.home'),

这是一个最简单的用法。转到127.0.0.1:8000/hello意味着对hello()函数的请求,转到127.0.0.1:8000/home将返回index.html并替换所要求的所有变量(现在你可能已经知道了所有这些)。

现在让我们讨论AJAX。AJAX调用是执行异步请求的客户端代码。这听起来很复杂,但它只是意味着它在后台为您执行请求,然后处理响应。当你对某个URL进行AJAX调用时,你得到的数据和用户访问那个地方时得到的数据是一样的。

例如,对127.0.0.1:8000/hello的AJAX调用将返回与访问它相同的内容。只是这一次,您将它放在JavaScript函数中,并且可以随心所欲地处理它。让我们看一个简单的用例:

$.ajax({
url: '127.0.0.1:8000/hello',
type: 'get', // This is the default though, you don't actually need to always mention it
success: function(data) {
alert(data);
},
failure: function(data) {
alert('Got an error dude');
}
});

一般过程是这样的:

  1. 该调用指向URL 127.0.0.1:8000/hello,就好像你打开了一个新选项卡并自己做一样。
  2. 如果成功(状态码200),执行成功函数,它将提醒接收到的数据。
  3. 如果失败,做一个不同的功能。

现在会发生什么呢?你会得到一个带有hello world的提醒。如果对home进行AJAX调用会发生什么?同样的,你会得到一个声明<h1>Hello world, welcome to my awesome site</h1>的警告。

换句话说,AJAX调用并不是什么新鲜事。它们只是让用户在不离开页面的情况下获得数据和信息的一种方式,它使你的网站设计流畅而整洁。你应该注意以下几点:

  1. 学习jQuery。这一点我怎么强调都不为过。你必须对它有所了解才能知道如何处理你收到的数据。您还需要了解一些基本的JavaScript语法(与python相差不远,您会习惯它)。我强烈推荐Envato的jQuery视频教程,它们很棒,会让你走上正确的道路。
  2. 何时使用JSON?。你会看到很多例子,Django视图发送的数据是JSON格式的。我没有详细说明这一点,因为如何做这件事并不重要(有很多解释),更重要的是。答案是,JSON数据是序列化的数据。也就是说,您可以操纵数据。正如我提到的,AJAX调用将获取响应,就像用户自己做的一样。现在假设你不想打乱所有的html,而是想发送数据(可能是一个对象列表)。JSON在这方面很好,因为它将数据作为对象发送(JSON数据看起来像一个python字典),然后您可以遍历它或做其他事情,从而无需筛选无用的html。
  3. 最后添加。当你构建一个web应用程序并想要实现AJAX时,请帮自己一个忙。首先,构建完全不使用AJAX的整个应用程序。确保一切正常运转。然后,也只有在那时,才开始编写AJAX调用。这是一个很好的过程,可以帮助你学到很多东西。
  4. 使用chrome的开发工具。由于AJAX调用是在后台完成的,因此有时很难调试它们。你应该使用chrome开发工具(或类似的工具,如firebug)和console.log的东西来调试。我就不详细解释了,随便打听打听吧。这对你很有帮助。
  5. CSRF意识。最后,记住Django中的post请求需要csrf_token。使用AJAX调用,很多时候您希望在不刷新页面的情况下发送数据。在你最终记住这一点之前,你可能会遇到一些麻烦——等等,你忘记发送csrf_token。这是AJAX-Django集成的一个众所周知的初学者障碍,但是在你学会如何让它更好地运行之后,它就变得很容易了。

这就是我想到的一切。这是一个庞大的主题,但是是的,可能没有足够的例子。慢慢地,慢慢地,你最终会成功的。

除了yuvi的精彩回答之外,我还想添加一个关于如何在Django中处理这个问题的小具体示例(超出将使用的任何js)。该示例使用AjaxableResponseMixin并假设Author模型。

import json


from django.http import HttpResponse
from django.views.generic.edit import CreateView
from myapp.models import Author


class AjaxableResponseMixin(object):
"""
Mixin to add AJAX support to a form.
Must be used with an object-based FormView (e.g. CreateView)
"""
def render_to_json_response(self, context, **response_kwargs):
data = json.dumps(context)
response_kwargs['content_type'] = 'application/json'
return HttpResponse(data, **response_kwargs)


def form_invalid(self, form):
response = super(AjaxableResponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return self.render_to_json_response(form.errors, status=400)
else:
return response


def form_valid(self, form):
# We make sure to call the parent's form_valid() method because
# it might do some processing (in the case of CreateView, it will
# call form.save() for example).
response = super(AjaxableResponseMixin, self).form_valid(form)
if self.request.is_ajax():
data = {
'pk': self.object.pk,
}
return self.render_to_json_response(data)
else:
return response


class AuthorCreate(AjaxableResponseMixin, CreateView):
model = Author
fields = ['name']

来源:Django文档,基于类的视图的表单处理

Django 1.6版本的链接更新到1.11版本后不再可用

简单而美好。你不必改变你的观点。Bjax处理所有链接。看看这个: Bjax < / p >

用法:

<script src="bjax.min.js" type="text/javascript"></script>
<link href="bjax.min.css" rel="stylesheet" type="text/css" />

最后,在你的html的HEAD中包含这个:

$('a').bjax();

更多设置,checkout demo在这里: Bjax演示 < / p >

我试图在我的项目中使用AjaxableResponseMixin,但最终出现以下错误消息:

配置不正确:没有URL重定向到。要么提供一个url,要么在Model上定义一个get_absolute_url方法。

这是因为当你向浏览器发送JSON请求时,CreateView将返回一个重定向响应而不是返回一个HttpResponse。所以我对AjaxableResponseMixin做了一些更改。如果请求是ajax请求,它不会调用super.form_valid方法,而是直接调用form.save()方法。

from django.http import JsonResponse
from django import forms
from django.db import models


class AjaxableResponseMixin(object):
success_return_code = 1
error_return_code = 0
"""
Mixin to add AJAX support to a form.
Must be used with an object-based FormView (e.g. CreateView)
"""
def form_invalid(self, form):
response = super(AjaxableResponseMixin, self).form_invalid(form)
if self.request.is_ajax():
form.errors.update({'result': self.error_return_code})
return JsonResponse(form.errors, status=400)
else:
return response


def form_valid(self, form):
# We make sure to call the parent's form_valid() method because
# it might do some processing (in the case of CreateView, it will
# call form.save() for example).
if self.request.is_ajax():
self.object = form.save()
data = {
'result': self.success_return_code
}
return JsonResponse(data)
else:
response = super(AjaxableResponseMixin, self).form_valid(form)
return response


class Product(models.Model):
name = models.CharField('product name', max_length=255)


class ProductAddForm(forms.ModelForm):
'''
Product add form
'''
class Meta:
model = Product
exclude = ['id']




class PriceUnitAddView(AjaxableResponseMixin, CreateView):
'''
Product add view
'''
model = Product
form_class = ProductAddForm

我写这篇文章是因为公认的答案太老了,它需要更新。

这就是我在2019年将Ajax与Django集成的方式:)让我们举一个什么时候需要Ajax的真实例子:-

假设我有一个注册用户名的模型,在Ajax的帮助下,我想知道一个给定的用户名是否存在。

html:

<p id="response_msg"></p>
<form id="username_exists_form" method='GET'>
Name: <input type="username" name="username" />
<button type='submit'> Check </button>
</form>

ajax:

$('#username_exists_form').on('submit',function(e){
e.preventDefault();
var username = $(this).find('input').val();
$.get('/exists/',
{'username': username},
function(response){ $('#response_msg').text(response.msg); }
);
});

urls . py:

from django.contrib import admin
from django.urls import path
from . import views


urlpatterns = [
path('admin/', admin.site.urls),
path('exists/', views.username_exists, name='exists'),
]

views.py:

def username_exists(request):
data = {'msg':''}
if request.method == 'GET':
username = request.GET.get('username').lower()
exists = Usernames.objects.filter(name=username).exists()
data['msg'] = username
data['msg'] += ' already exists.' if exists else ' does not exists.'
return JsonResponse(data)

此外,render_to_response已弃用,已被渲染取代,从Django 1.7开始,我们使用JsonResponse代替HttpResponse进行ajax响应。因为它带有JSON编码器,所以在返回响应对象之前不需要序列化数据,但HttpResponse不弃用。

AJAX是执行异步任务的最佳方式。异步调用在任何网站建设中都很常见。我们将通过一个简短的例子来学习如何在Django中实现AJAX。我们需要使用jQuery来写更少的javascript。

这是联系的例子,这是最简单的例子,我用它来解释AJAX的基础知识和它在Django中的实现。在本例中,我们将发出POST请求。我正在遵循这篇文章中的一个例子:https://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django

models.py

让我们首先创建Contact模型,其中包含基本细节。

from django.db import models


class Contact(models.Model):
name = models.CharField(max_length = 100)
email = models.EmailField()
message = models.TextField()
timestamp = models.DateTimeField(auto_now_add = True)


def __str__(self):
return self.name

forms.py

为上面的模型创建表单。

from django import forms
from .models import Contact


class ContactForm(forms.ModelForm):
class Meta:
model = Contact
exclude = ["timestamp", ]

views.py

视图看起来类似于基本的基于函数的创建视图,但是我们使用JsonResponse响应而不是返回呈现。

from django.http import JsonResponse
from .forms import ContactForm


def postContact(request):
if request.method == "POST" and request.is_ajax():
form = ContactForm(request.POST)
form.save()
return JsonResponse({"success":True}, status=200)
return JsonResponse({"success":False}, status=400)

urls . py

让我们创建上面视图的路由。

from django.contrib import admin
from django.urls import path
from app_1 import views as app1


urlpatterns = [
path('ajax/contact', app1.postContact, name ='contact_submit'),
]

模板

移动到前端部分,呈现上面创建的包含csrf_token和提交按钮的表单。注意,我们已经包含了jquery库。

<form id = "contactForm" method= "POST">{% csrf_token %}
\{\{ contactForm.as_p }}
<input type="submit" name="contact-submit" class="btn btn-primary" />
</form>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Javascript

现在我们来谈谈javascript部分,在表单提交中,我们发出POST类型的ajax请求,获取表单数据并发送到服务器端。

$("#contactForm").submit(function(e){
// prevent from normal form behaviour
e.preventDefault();
// serialize the form data
var serializedData = $(this).serialize();
$.ajax({
type : 'POST',
url :  "{% url 'contact_submit' %}",
data : serializedData,
success : function(response){
//reset the form after successful submit
$("#contactForm")[0].reset();
},
error : function(response){
console.log(response)
}
});
});


这只是一个开始使用django使用AJAX的基本示例,如果你想了解更多的示例,你可以通过本文:https://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django

当我们使用Django时:

Server ===> Client(Browser)
Send a page


When you click button and send the form,
----------------------------
Server <=== Client(Browser)
Give data back. (data in form will be lost)
Server ===> Client(Browser)
Send a page after doing sth with these data
----------------------------

如果希望保留旧数据,可以不使用Ajax。(页面会刷新)

Server ===> Client(Browser)
Send a page
Server <=== Client(Browser)
Give data back. (data in form will be lost)
Server ===> Client(Browser)
1. Send a page after doing sth with data
2. Insert data into form and make it like before.
After these thing, server will send a html page to client. It means that server do more work, however, the way to work is same.

或者你可以用Ajax(页面不会刷新)

--------------------------
<Initialization>
Server ===> Client(Browser) [from URL1]
Give a page
--------------------------
<Communication>
Server <=== Client(Browser)
Give data struct back but not to refresh the page.
Server ===> Client(Browser) [from URL2]
Give a data struct(such as JSON)
---------------------------------

如果你使用Ajax,你必须做到这些:

  1. 使用URL1初始化一个HTML页面(我们通常使用Django模板初始化页面)。然后服务器发送一个html页面给客户端。
  2. 使用Ajax使用URL2与服务器通信。然后服务器端向客户端发送一个数据结构。

Django不同于Ajax。原因如下:

  • 返还给客户的东西是不一样的。Django的案例是HTML页面。Ajax的案例是数据结构。
  • Django擅长创建一些东西,但它只能创建一次,它不能改变任何东西。姜戈就像一部动漫,由很多画面组成。相比之下,Ajax并不擅长创建,但擅长在现有的html页面中更改。

在我看来,如果你想到处使用ajax。当你需要用数据初始化页面时,你可以使用Django和Ajax。但在某些情况下,你只需要一个静态页面,不需要从服务器上获取任何东西,你不需要使用Django模板。

如果您认为Ajax不是最佳实践。你可以使用Django模板来做任何事情,比如动画。

(我的英语不好)

使用Django轻松调用ajax

< p > (26.10.2020)
在我看来,这比正确答案更清晰、更简单。这一个还包括如何添加csrftoken和使用ajax的login_required方法

视图

@login_required
def some_view(request):
"""Returns a json response to an ajax call. (request.user is available in view)"""
# Fetch the attributes from the request body
data_attribute = request.GET.get('some_attribute')  # Make sure to use POST/GET correctly
# DO SOMETHING...
return JsonResponse(data={}, status=200)

urls . py

urlpatterns = [
path('some-view-does-something/', views.some_view, name='doing-something'),
]

ajax调用

ajax调用非常简单,但对于大多数情况来说已经足够了。您可以获取一些值并将它们放入数据对象中,然后在上面描述的视图中,您可以通过它们的名称再次获取它们的值。

你可以在django的文档中找到csrftoken函数。基本上只是复制它,并确保在ajax调用之前呈现它,以便定义csrftoken变量

$.ajax({
url: "{% url 'doing-something' %}",
headers: {'X-CSRFToken': csrftoken},
data: {'some_attribute': some_value},
type: "GET",
dataType: 'json',
success: function (data) {
if (data) {
console.log(data);
// call function to do something with data
process_data_function(data);
}
}
});

使用ajax将HTML添加到当前页面

这可能有点离题,但我很少看到这个使用,这是一个伟大的方式来减少窗口重定位以及手动html字符串创建javascript。

这与上面的非常相似,但这一次我们从响应中呈现html,而不需要重新加载当前窗口。

如果您打算从作为ajax调用响应接收到的数据中呈现某种html,那么从视图返回HttpResponse而不是JsonResponse可能会更容易。这允许您轻松地创建html,然后可以插入到元素中。

视图

# The login required part is of course optional
@login_required
def create_some_html(request):
"""In this particular example we are filtering some model by a constraint sent in by
ajax and creating html to send back for those models who match the search"""
# Fetch the attributes from the request body (sent in ajax data)
search_input = request.GET.get('search_input')


# Get some data that we want to render to the template
if search_input:
data = MyModel.objects.filter(name__contains=search_input) # Example
else:
data = []


# Creating an html string using template and some data
html_response = render_to_string('path/to/creation_template.html', context = {'models': data})


return HttpResponse(html_response, status=200)

视图的html创建模板

creation_template.html

{% for model in models %}
<li class="xyz">\{\{ model.name }}</li>
{% endfor %}

urls . py

urlpatterns = [
path('get-html/', views.create_some_html, name='get-html'),
]

主模板和ajax调用

这就是我们要向其中添加数据的模板。在这个例子中,我们有一个搜索输入和一个将搜索输入值发送到视图的按钮。然后视图返回一个HttpResponse,显示与我们可以在元素中呈现的搜索匹配的数据。

{% extends 'base.html' %}
{% load static %}
{% block content %}
<input id="search-input" placeholder="Type something..." value="">
<button id="add-html-button" class="btn btn-primary">Add Html</button>
<ul id="add-html-here">
<!-- This is where we want to render new html -->
</ul>
{% end block %}


{% block extra_js %}
<script>
// When button is pressed fetch inner html of ul
$("#add-html-button").on('click', function (e){
e.preventDefault();
let search_input = $('#search-input').val();
let target_element = $('#add-html-here');
$.ajax({
url: "{% url 'get-html' %}",
headers: {'X-CSRFToken': csrftoken},
data: {'search_input': search_input},
type: "GET",
dataType: 'html',
success: function (data) {
if (data) {
console.log(data);
// Add the http response to element
target_element.html(data);
}
}
});
})
</script>
{% endblock %}