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


264

我是Django的新手,而Ajax的新手。我正在一个需要将两者整合的项目中。我相信我理解它们背后的原理,但是并没有找到对两者的良好解释。

有人可以给我一个简短的解释,说明如何将两者集成在一起才能更改代码库?

例如,我仍然可以将HttpResponseAjax与一起使用,还是必须随着Ajax的使用而改变我的回答?如果是这样,请您举例说明如何更改请求的响应?如果有什么不同,我返回的数据是JSON。

Answers:


637

即使这不完全符合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调用时,您将获得与访问该位置的用户相同的数据。

例如,对的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');
    }
}); 

一般过程是这样的:

  1. 127.0.0.1:8000/hello就像您打开一个新标签页并自己完成一样,呼叫将转到URL 。
  2. 如果成功(状态码200),请执行成功功能,这将提醒收到的数据。
  3. 如果失败,请执行其他功能。

现在在这里会发生什么?您会收到有关“ hello world”的警报。如果您拨打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要调试的东西。我不会详细解释,只是在Google周围寻找它。这对您会非常有帮助。
  5. CSRF意识。最后,请记住Django中的发布请求需要csrf_token。通过AJAX调用,很多时候您想发送数据而不刷新页面。您可能会遇到一些麻烦,最后才想起那个-等待,您忘记了发送csrf_token。这是AJAX-Django集成中的一个已知的初学者障碍,但是当您学习了如何使其变得更好时,它就像馅饼一样容易。

这就是我想到的一切。这是一个广泛的主题,但是,可能没有足够的例子。只要按照自己的方式做,就慢慢地,最终会得到它。


1
谢谢。我只是去过你那里,我知道那种感觉。至于聊天-一般是,但现在不行(另外,对于特定问题,您还有...整个SO的全部内容)。
yuvi

2
PS我链接的视频有整整一周的时间致力于AJAX。认真地,通过他们。他们太棒了
yuvi 2013年

感谢@yuvi!我问自己关于AJAX的相同问题。另外,我不确定何时必须使用AJAX。例如,我知道我需要一些Java脚本来处理Bootstrap模态形式,但我不知道它是否与AJAX相关。认真,不必了解整个Jquery的只是为了显示弹出在我的网页...我不能看到投资:(回报是否有更简单的替代:(再次感谢你的答案?
大卫D.14年

5
@DavidW。大卫您好,我很高兴我的回答对您有所帮助。AJAX是一种技术,您可以使用简单的javascript来完成,但是会变得非常复杂。jQuery仅具有使它变得更容易的快捷方式。它与Bootstrap的模式无关(您可以根据需要通过AJAX获取表单,但在其他方面则无关)。无论如何,我强烈建议您尝试慢慢解决问题。jQuery如今非常重要,而且非常基础,因此在这里有不错的投资。当您遇到障碍时,请SO提出问题(不在已回答问题的注释中,在此处打开一个新的问题)。祝好运!
尤维2014年

关于您的提及csrf_token,我们可以解决该方法吗?如果我们有一个示例函数,ajaxCall()我们可以使用类似的传统方法<form onsubmit='ajaxCall();return false;'>,对吗?
ytpillai

22

除了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版


14

我写这封信是因为可接受的答案很旧,需要复习。

所以这就是我在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'),
]

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()
        if exists:
            data['msg'] = username + ' already exists.'
        else:
            data['msg'] = username + ' does not exists.'
    return JsonResponse(data)

同样不推荐使用的render_to_response已被render取代,从Django 1.7起,而不是HttpResponse,我们使用JsonResponse进行Ajax响应。因为它带有JSON编码器,所以您不需要在返回响应对象之前对数据进行序列化,但HttpResponse不建议使用。


8

简单而漂亮。您无需更改视图。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演示


18
嗨,快速笔记-我想建议刚开始学习Django和/或AJAX的任何人-请不要使用它。你什么也不会学。将其保存在您的收藏夹中,并自行构建AJAX请求。一旦您已经熟悉了Bjax在后台的工作原理,请回来使用它。这并不像告诉人们学习汇编语言以进行编码-您不需要使用纯JS(仅使用jQuery)来构建AJAX请求,因为如果您想成为一名专业人士,那便是最低的基础知识需要有。干杯
yuvi 2015年

5

AJAX是执行异步任务的最佳方法。在任何网站建设中,进行异步调用都是很常见的事情。我们将以一个简短的例子来学习如何在Django中实现AJAX。我们需要使用jQuery,以便减少JavaScript。

这是Contact示例,这是最简单的示例,我用它来解释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

表格

创建上述模型的表单。

from django import forms
from .models import Contact

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

views.py

这些视图看起来类似于基于功能的基本创建视图,但是我们不使用render来返回,而是使用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和Submit按钮。请注意,我们已经包含了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>

Java脚本

现在让我们谈谈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-在Django中实现ajax


2

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

配置不正确:没有要重定向到的URL。在模型上提供一个URL或定义一个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

0

当我们使用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擅长创建某些东西,但是只能创建一次,不能更改任何东西。Django就像动漫,由许多图片组成。相比之下,Ajax并不擅长于在现有的html页面中创建某事,但擅长于更改某事。

我认为,如果您想在任何地方使用ajax。当您首先需要使用数据初始化页面时,可以将Django与Ajax结合使用。但是在某些情况下,您只需要一个静态页面,而服务器上没有任何内容,则不需要使用Django模板。

如果您不认为Ajax是最佳实践。您可以使用Django模板来完成所有操作,例如动漫。

(我英文不太好)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.