如何将 Ajax 与 Django 应用程序集成?
- 2024-12-20 08:37:00
- admin 原创
- 165
问题描述:
我是 Django 的新手,对 Ajax 也相当陌生。我正在做一个需要将两者整合在一起的项目。我相信我理解它们背后的原理,但还没有找到将两者结合起来的很好的解释。
有人可以简单解释一下当它们两个集成在一起时代码库必须如何改变吗?
例如,我是否仍可以使用HttpResponse
Ajax,或者我的响应是否必须随着 Ajax 的使用而改变?如果是这样,您能否提供一个示例,说明对请求的响应必须如何改变?如果有任何不同,我返回的数据是 JSON。
解决方案 1:
尽管这不完全符合 SO 的精神,但我还是喜欢这个问题,因为我刚开始的时候也遇到过同样的问题,所以我会给你一个快速指南。显然你不了解它们背后的原理(不要认为这是冒犯,但如果你了解的话你就不会问了)。
Django 是服务器端的。这意味着,假设客户端访问一个 URL,你有一个函数views
可以渲染他看到的内容并以 HTML 形式返回响应。让我们将其分解为几个示例:
视图.py:
def hello(request):
return HttpResponse('Hello World!')
def home(request):
return render_to_response('index.html', {'variable': 'world'})
索引.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 调用时,您会获得与用户访问该位置时相同的数据。
例如,AJAX 调用127.0.0.1:8000/hello
将返回与您访问它时相同的内容。只是这一次,您将其放在 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');
}
});
大致过程如下:
调用会转到 URL,
127.0.0.1:8000/hello
就像您自己打开新标签并执行操作一样。如果成功(状态代码 200),则执行成功函数,这将提醒收到的数据。
如果失败,则执行不同的功能。
现在会发生什么?您将收到一条包含“hello world”的警报。如果您对 home 进行 AJAX 调用会发生什么?同样,您将收到一条警报,内容为<h1>Hello world, welcome to my awesome site</h1>
。
换句话说 - AJAX 调用并不是什么新鲜事。它们只是一种让用户无需离开页面即可获取数据和信息的方式,它使您的网站设计变得流畅且非常整洁。您应该注意以下几条准则:
学习 jQuery。我再怎么强调也不为过。你必须了解一点 jQuery,才能知道如何处理收到的数据。你还需要了解一些基本的 JavaScript 语法(与 Python 相差不远,你会习惯的)。我强烈推荐Envato 的 jQuery 视频教程,它们很棒,会让你走上正确的道路。
何时使用 JSON?。您将看到很多示例,其中 Django 视图发送的数据是 JSON 格式的。我没有详细介绍这一点,因为怎么做并不重要(有很多解释),何时使用才更重要。答案是 - JSON 数据是序列化数据。也就是说,您可以操作数据。正如我所提到的,AJAX 调用将获取响应,就好像用户自己做的那样。现在假设您不想弄乱所有 html,而是想要发送数据(可能是对象列表)。JSON 非常适合这种情况,因为它将其作为对象发送(JSON 数据看起来像 Python 字典),然后您可以对其进行迭代或执行其他操作,从而无需筛选无用的 html。
最后添加它。当您构建 Web 应用程序并想要实现 AJAX 时 - 请帮自己一个忙。首先,构建完全没有任何 AJAX 的整个应用程序。确保一切正常。然后,也只有这样,才开始编写 AJAX 调用。这是一个很好的过程,可以帮助您学到很多东西。
使用 chrome 的开发者工具。由于 AJAX 调用是在后台完成的,因此有时很难调试它们。您应该使用 chrome 开发者工具(或类似工具,如 firebug)和其他
console.log
工具进行调试。我不会详细解释,只需在 google 上搜索并了解它。这对您非常有帮助。CSRF 意识。最后,请记住,Django 中的发布请求需要
csrf_token
。使用 AJAX 调用时,很多时候您都希望在不刷新页面的情况下发送数据。在您最终记起这一点之前,您可能会遇到一些麻烦 - 等等,您忘了发送csrf_token
。这是 AJAX-Django 集成中已知的初学者障碍,但在您学会如何使其运行良好之后,它就变得轻而易举了。
以上就是我想到的全部内容。这是一个庞大的话题,但确实,可能没有足够的例子。只要你慢慢来,最终你就会明白。
解决方案 2:
除了 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 版
解决方案 3:
我写这篇文章是因为接受的答案已经很老了,需要复习一下。
这就是我在 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>
阿贾克斯:
$('#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'),
]
视图.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已被弃用,并已被render取代,从 Django 1.7 开始,我们使用JsonResponse代替HttpResponse进行 ajax 响应。因为它带有 JSON 编码器,所以您不需要在返回响应对象之前序列化数据,但它并未被弃用。HttpResponse
解决方案 4:
简单又好用。您无需更改视图。Bjax 处理您的所有链接。查看:
Bjax
用法:
<script src="bjax.min.js" type="text/javascript"></script>
<link href="bjax.min.css" rel="stylesheet" type="text/css" />
最后,将其包含在你的 html 的 HEAD 中:
$('a').bjax();
有关更多设置,请查看此处的演示:
Bjax 演示
解决方案 5:
AJAX 是执行异步任务的最佳方式。在任何网站建设中,进行异步调用都是常用的方法。我们将通过一个简短的示例来了解如何在 Django 中实现 AJAX。我们需要使用 jQuery 来减少编写 javascript。
这是联系人示例,也是最简单的示例,我用它来解释 AJAX 的基础知识及其在 Django 中的实现。我们将在此示例中发出 POST 请求。我遵循此帖子中的一个示例:https ://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django
模型.py
让我们首先创建联系人模型,包含基本细节。
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
表单.py
为上述模型创建表单。
from django import forms
from .models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
exclude = ["timestamp", ]
视图.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
解决方案 6:
使用 Django 轻松进行 ajax 调用
(2020 年 10 月 26 日)
我认为这比正确答案更简洁。此答案还包括如何添加 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 添加到当前页面
这可能有点偏离主题,但我很少看到这种用法,它是最小化窗口重定位以及在 javascript 中手动创建 html 字符串的好方法。
这与上面的非常相似,但这次我们从响应中呈现 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 创建模板
创作模板.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 %}
解决方案 7:
我曾尝试在我的项目中使用AjaxableResponseMixin,但最终出现以下错误消息:
配置不当:没有可重定向到的 URL。请提供一个 URL 或在模型上定义 get_absolute_url 方法。
这是因为当你向浏览器发送 JSON 请求时,CreateView 将返回重定向响应,AjaxableResponseMixin
而不是返回 HttpResponse。所以我对 做了一些修改。如果请求是 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
解决方案 8:
当我们使用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,则必须执行以下操作:
使用 URL1 初始化一个 HTML 页面(我们通常使用 Django 模板初始化页面)。然后服务器向客户端发送一个 HTML 页面。
使用 Ajax 通过 URL2 与服务器通信。然后服务器向客户端发送数据结构。
Django 与 Ajax 有所不同。其原因如下:
返回给客户端的东西不一样,Django的情况是HTML页面,Ajax的情况是数据结构。
Django 擅长创建一些东西,但它只能创建一次,无法改变任何东西。Django 就像动漫,由许多图片组成。相比之下,Ajax 不擅长创建某物,但擅长在现有的 html 页面中更改某物。
我认为,如果你想在任何地方使用 ajax。当你需要首先用数据初始化一个页面时,你可以使用 Django 和 Ajax。但在某些情况下,你只需要一个静态页面而不需要任何来自服务器的东西,你就不需要使用 Django 模板。
如果您认为 Ajax 不是最佳实践,您可以使用 Django 模板来做所有事情,比如动漫。
(我的英语不好)
解决方案 9:
这里给出的示例展示了如何处理 ajax 以提交表单或获取一些 html 代码以显示给用户。它们成功地向您展示了如何使用 Django 原生实现这一点。感谢大家提供的高质量答案。
AJAX 的另一个非常常见的用例是进行CRUD 操作:使用 AJAX 调用从客户端读取、创建、更新、删除对象。
非常流行的django rest 框架非常适合。它学习起来非常快,看起来像具有通用视图的原生 Django。它可以原生处理 CRUD 操作,并且旨在让您自定义任何您想要的内容,身份验证、权限、分页、验证……它实际上非常适合构建 API 端点。
在简单模型上创建 CRUD 操作的示例:
模型
class MyModel(models.Model):
name = models.CharField()
序列化器
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
看法
class MyModelViewSet(viewsets.ModelViewSet):
"""
A simple ViewSet for viewing and editing MyModel
"""
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
permission_classes = [IsAuthenticated]
urlconf
router = DefaultRouter()
router.register(r'mymodels', MyModelViewSet, basename='mymodel')
urlpatterns = router.urls
JavaScript 部分:
列表
$.ajax({
url: '127.0.0.1:8000/mymodels',
type: 'get',
dataType: 'json',
success: function(data) {
console.log(data); // the list of your objects
}
});
细节
$.ajax({
url: '127.0.0.1:8000/mymodels/123',
type: 'get',
dataType: 'json',
success: function(data) {
console.log(data); // the detail of an object with the primary key 123
}
});
创造
$.ajax({
url: '127.0.0.1:8000/mymodels',
type: 'post',
data: JSON.stringify({name: 'a new model'}),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function(data) {
console.log(data); // the detail of the object created
}
});
更新
$.ajax({
url: '127.0.0.1:8000/mymodels/123',
type: 'put',
data: JSON.stringify({name: 'the name updated'}),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function(data) {
console.log(data); // the detail of the object updated
}
});
删除
$.ajax({
url: '127.0.0.1:8000/mymodels/123',
type: 'delete',
success: function(data) {
console.log("the object is deleted");
}
});
希望有帮助