Как интегрировать Ajax с приложениями Django?
Я новичок в Django и довольно новичок в Ajax. Я работаю над проектом, в котором мне нужно интегрировать оба. Я считаю, что понимаю принципы, лежащие в их основе, но не нашел хорошего объяснения двух вместе.
Может ли кто-нибудь дать мне быстрое объяснение того, как кодовая база должна измениться, когда они интегрируются вместе?
Например, могу ли я использовать HttpResponse
с Ajax, или мои ответы должны измениться с использованием Ajax? Если да, не могли бы вы привести пример того, как должны изменяться ответы на запросы? Если это имеет какое-то значение, я возвращаю данные в формате JSON.
4 ответа
Хотя это не совсем в духе ТАК, мне нравится этот вопрос, потому что у меня были те же проблемы, когда я начинал, поэтому я дам вам краткое руководство. Очевидно, вы не понимаете принципы, стоящие за ними (не воспринимайте это как оскорбление, но если бы вы это сделали, вы бы не спрашивали).
Джанго на стороне сервера. Это означает, что клиент говорит, что у вас есть функция внутри представлений, которая отображает то, что он видит, и возвращает ответ в 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
означает запрос к функции приветствия, идущий к 127.0.0.1:8000/home
вернет index.html
и замените все переменные в соответствии с запросом (вы, наверное, уже знаете все это)
Теперь поговорим об AJAX. AJAX -вызовы - это код на стороне клиента, выполняющий асинхронные запросы. Это звучит сложно, но это просто означает, что он делает запрос для вас в фоновом режиме, а затем обрабатывает ответ. Поэтому, когда вы выполняете AJAX -вызов для некоторого URL-адреса, вы получаете те же данные, что и пользователь, отправляющийся в это место.
Например, ajax вызов 127.0.0.1:8000/hello
вернет то же самое, что и при посещении. Только на этот раз у вас есть это внутри функции js, и вы можете иметь дело с этим, как захотите. Давайте посмотрим на простой случай использования:
$.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), выполните функцию успеха, которая предупредит полученные данные.
- Если не получается, сделайте другую функцию.
Что теперь будет здесь? Вы получите предупреждение с "Привет мир" в нем. Что произойдет, если вы сделаете Ajax звонок домой? То же самое, вы получите предупреждение о том, <h1>Hello world, welcome to my awesome site</h1>
,
Другими словами, в вызовах AJAX нет ничего нового. Это просто способ дать вам возможность получать данные и информацию, не покидая страницы, и это обеспечивает плавный и очень аккуратный дизайн вашего сайта. Несколько рекомендаций, которые вы должны принять к сведению:
- Изучите JQuery. Я не могу подчеркнуть это достаточно. Вам нужно немного это понять, чтобы понять, как обращаться с полученными вами данными. Вам также необходимо понять некоторый базовый синтаксис JavaScript (недалеко от Python, вы привыкнете к нему). Я настоятельно рекомендую видеоуроки Envato для jQuery, они великолепны и помогут вам выбрать правильный путь.
- Когда использовать JSON?, Вы увидите много примеров, когда данные, отправляемые представлениями Django, находятся в формате JSON. Я не стал вдаваться в подробности, потому что не важно, как это сделать (имеется множество объяснений), и гораздо важнее, когда. И ответ на этот вопрос - данные JSON являются сериализованными данными. То есть данными, которыми вы можете манипулировать. Как я уже упоминал, AJAX -вызов будет получать ответ, как если бы пользователь сделал это сам. Теперь скажите, что вы не хотите связываться со всеми html-файлами, а вместо этого хотите отправлять данные (возможно, список объектов). JSON хорош для этого, потому что он отправляет его как объект (данные JSON выглядят как словарь Python), а затем вы можете перебирать его или делать что-то еще, что устраняет необходимость просеивать бесполезный html.
- Добавьте это в последнюю очередь. Когда вы создаете веб-приложение и хотите внедрить AJAX - сделайте себе одолжение. Во-первых, создайте приложение полностью без AJAX. Смотри что все работает. Тогда и только тогда начните писать вызовы AJAX. Это хороший процесс, который также помогает вам многому научиться.
- Используйте инструменты разработчика Chrome. Поскольку AJAX -вызовы выполняются в фоновом режиме, иногда их очень трудно отладить. Вы должны использовать инструменты разработчика Chrome (или аналогичные инструменты, такие как firebug) и
console.log
вещи для отладки. Я не буду подробно объяснять, просто погуглите и узнайте об этом. Это было бы очень полезно для вас. - CSRF осведомленность. Наконец, помните, что почтовые запросы в Django требуют
csrf_token
, С вызовами AJAX, часто вы хотели бы отправлять данные без обновления страницы. Вы, вероятно, столкнетесь с некоторыми проблемами, прежде чем наконец вспомните об этом - подождите, вы забыли отправитьcsrf_token
, Это известное препятствие для начинающих в интеграции AJAX-Django, но после того, как вы узнаете, как заставить его играть хорошо, это просто как пирог.
Это все, что приходит мне в голову. Это обширная тема, но, да, вероятно, там недостаточно примеров. Просто прокладывайте себе путь, медленно, в конце концов, вы получите это.
В дополнение к отличному ответу yuvi я хотел бы добавить небольшой конкретный пример того, как с этим справляться в Django (помимо любых js, которые будут использоваться). В примере используются AjaxableResponseMixin
и предполагает модель автора.
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, Обработка форм с представлениями на основе классов.
Ссылка на версию 1.6 Django больше не доступна, обновлена до версии 1.11
Я пишу это, потому что принятый ответ довольно старый, он нуждается в обновлении.
Вот так я бы интегрировал Ajax с Django в 2019 году:) И давайте возьмем реальный пример того, когда нам понадобится 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()
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
не считается устаревшим
Просто и приятно. Вам не нужно менять свои взгляды. Bjax обрабатывает все ваши ссылки. Проверьте это: Bjax
Использование:
<script src="bjax.min.js" type="text/javascript"></script>
<link href="bjax.min.css" rel="stylesheet" type="text/css" />
Наконец, включите это в заголовок вашего HTML:
$('a').bjax();
Для получения дополнительных настроек, ознакомьтесь с демо здесь: Bjax Demo
AJAX - лучший способ выполнять асинхронные задачи. Выполнение асинхронных вызовов является обычным делом при создании любого веб-сайта. Мы рассмотрим короткий пример, чтобы узнать, как мы можем реализовать AJAX в Django. Нам нужно использовать jQuery, чтобы писать меньше javascript.
Это контактный пример, который является самым простым примером, который я использую для объяснения основ AJAX и его реализации в Django. Мы будем делать запрос POST в этом примере. Я следую одному из примеров этого поста: https://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django
models.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
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, при отправке формы мы делаем запрос ajax типа POST, принимаем данные формы и отправляем на сервер.
$("#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)
}
});
});
Это просто базовый пример, чтобы начать работу с AJAX с django. Если вы хотите получить погружение с несколькими другими примерами, вы можете просмотреть эту статью: https://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django
Простые вызовы ajax с помощью Django
(26.10.2020)
На мой взгляд, это намного проще и понятнее, чем правильный ответ. Это также включает в себя, как добавить csrftoken и использовать методы login_required с ajax.
Вид
@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 довольно прост, но его достаточно для большинства случаев. Вы можете получить некоторые значения и поместить их в объект данных, а затем в представлении, изображенном выше, вы можете снова получить их значения через их имена.
Вы можете найти функцию csrftoken в документации django. В основном просто скопируйте его и убедитесь, что он отображается перед вашим вызовом 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);
}
}
});
Добавить HTML на текущую страницу с помощью ajax
Это может быть немного не по теме, но я редко видел, чтобы это использовалось, и это отличный способ минимизировать перемещение окон, а также ручное создание строки html в javascript.
Это очень похоже на приведенное выше, но на этот раз мы визуализируем html из ответа без перезагрузки текущего окна.
Если вы намеревались отобразить какой-то html из данных, которые вы получите в ответ на вызов ajax, может быть проще отправить 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 %}
Я пытался использовать AjaxableResponseMixin в моем проекте, но в результате получилось следующее сообщение об ошибке:
Неправильно настроен: нет URL для перенаправления. Либо укажите URL-адрес, либо определите метод get_absolute_url в модели.
Это потому, что CreateView будет возвращать ответ перенаправления вместо возврата HttpResponse, когда вы отправляете запрос JSON в браузер. Поэтому я внес некоторые изменения в 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
Когда мы используем 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, вы должны сделать следующее:
- Начните HTML-страницу, используя URL1 (обычно мы начинаем страницу с помощью шаблона Django). И затем сервер отправляет клиенту html-страницу.
- Используйте Ajax для связи с сервером с помощью URL2. И затем сервер отправляет клиенту структуру данных.
Django отличается от Ajax. Причина этого в следующем:
- Вещь возврата клиенту отличается. Случай Django - это HTML-страница. Случай Ajax - структура данных.
- Django хорош в создании чего-либо, но он может создать только один раз, он не может ничего изменить. Джанго похож на аниме, состоит из множества картинок. Напротив, Ajax не годится для создания sth, но хорош для изменения sth на существующей странице html.
На мой взгляд, если вы хотите использовать ajax везде. когда вам нужно сначала инициализировать страницу данными, вы можете использовать Django с Ajax. Но в некоторых случаях вам просто нужна статическая страница без чего-либо с сервера, вам не нужно использовать шаблон Django.
Если вы не думаете, что Ajax - лучшая практика. вы можете использовать шаблон Django, чтобы делать все, например аниме.
(Мой английский не очень хорош)