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

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

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


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

Django是服务器端。这意味着,假设客户端访问一个URL,您在视图中有一个函数,可以呈现他所看到的内容并以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');
    }
}); 

一般过程是这样的:

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

现在会发生什么呢?你会得到一个带有hello world的提醒。如果对home进行AJAX调用会发生什么?同样的事情,你会得到一个警告,说明<h1>你好世界,欢迎来到我的精彩网站</h1>。

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

Learn jQuery. I cannot stress this enough. You're gonna have to understand it a little to know how to handle the data you receive. You'll also need to understand some basic JavaScript syntax (not far from python, you'll get used to it). I strongly recommend Envato's video tutorials for jQuery, they are great and will put you on the right path. When to use JSON?. You're going to see a lot of examples where the data sent by the Django views is in JSON. I didn't go into detail on that, because it isn't important how to do it (there are plenty of explanations abound) and a lot more important when. And the answer to that is - JSON data is serialized data. That is, data you can manipulate. Like I mentioned, an AJAX call will fetch the response as if the user did it himself. Now say you don't want to mess with all the html, and instead want to send data (a list of objects perhaps). JSON is good for this, because it sends it as an object (JSON data looks like a python dictionary), and then you can iterate over it or do something else that removes the need to sift through useless html. Add it last. When you build a web app and want to implement AJAX - do yourself a favor. First, build the entire app completely devoid of any AJAX. See that everything is working. Then, and only then, start writing the AJAX calls. That's a good process that helps you learn a lot as well. Use chrome's developer tools. Since AJAX calls are done in the background it's sometimes very hard to debug them. You should use the chrome developer tools (or similar tools such as firebug) and console.log things to debug. I won't explain in detail, just google around and find out about it. It would be very helpful to you. CSRF awareness. Finally, remember that post requests in Django require the csrf_token. With AJAX calls, a lot of times you'd like to send data without refreshing the page. You'll probably face some trouble before you'd finally remember that - wait, you forgot to send the csrf_token. This is a known beginner roadblock in AJAX-Django integration, but after you learn how to make it play nice, it's easy as pie.

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

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

用法:

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

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

$('a').bjax();

欲了解更多设置,请在这里查看演示: Bjax演示

我尝试在我的项目中使用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>   

阿贾克斯:

$('#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,你必须做到这些:

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

Django不同于Ajax。原因如下:

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

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

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

(我的英语不好)

使用Django轻松调用ajax

(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 %}