Jak zintegrować Ajax z aplikacjami Django?

264

Jestem nowy w Django i całkiem nowy w Ajaxie. Pracuję nad projektem, w którym muszę je zintegrować. Wierzę, że rozumiem zasady stojące za nimi oboje, ale nie znalazłem dobrego wyjaśnienia tych dwóch zasad.

Czy ktoś mógłby mi szybko wyjaśnić, w jaki sposób baza kodów musi się zmienić, gdy obie zostaną zintegrowane?

Na przykład, czy nadal mogę używać HttpResponsez Ajaxem, czy moje odpowiedzi muszą się zmieniać przy użyciu Ajax? Jeśli tak, czy możesz podać przykład zmiany odpowiedzi na prośby? Jeśli robi to jakąkolwiek różnicę, zwracane przeze mnie dane to JSON.

tjons
źródło

Odpowiedzi:

637

Chociaż nie jest to całkowicie w duchu SO, uwielbiam to pytanie, ponieważ miałem takie same problemy, kiedy zaczynałem, więc dam ci krótki przewodnik. Oczywiście nie rozumiesz zasad leżących u ich podstaw (nie bierz tego za obrazę, ale jeśli byś to zrobił, nie pytałbyś).

Django jest po stronie serwera . To znaczy, powiedzmy, że klient idzie do adresu URL, masz w sobie funkcję, viewsktóra renderuje to, co widzi i zwraca odpowiedź w HTML. Podzielmy to na przykłady:

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'),

To przykład najprostszego użycia. Przejście do 127.0.0.1:8000/hellooznacza żądanie do hello()funkcji, przejście 127.0.0.1:8000/homezwróciindex.html i zastąpienie wszystkich zmiennych zgodnie z zapytaniem (prawdopodobnie już to wszystko znasz).

Porozmawiajmy teraz o AJAX . Wywołania AJAX to kod po stronie klienta, który wykonuje żądania asynchroniczne. To brzmi skomplikowanie, ale oznacza to po prostu, że wykonuje zapytanie w tle, a następnie obsługuje odpowiedź. Więc kiedy wykonujesz wywołanie AJAX dla jakiegoś adresu URL, otrzymujesz te same dane, które uzyskałbyś jako użytkownik jadący do tego miejsca.

Na przykład wywołanie AJAX 127.0.0.1:8000/hellozwróci to samo, co gdybyś go odwiedził. Tylko tym razem masz go wewnątrz funkcji JavaScript i możesz sobie z tym poradzić, jak chcesz. Spójrzmy na prosty przypadek użycia:

$.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');
    }
}); 

Ogólny proces jest następujący:

  1. Połączenie przechodzi na adres URL 127.0.0.1:8000/hello, jakbyś otworzył nową kartę i zrobił to sam.
  2. Jeśli się powiedzie (kod stanu 200), wykonaj funkcję powodzenia, która ostrzeże otrzymane dane.
  3. Jeśli się nie powiedzie, wykonaj inną funkcję.

Co by się tu stało? Pojawi się ostrzeżenie z „witaj światem”. Co się stanie, jeśli wykonasz połączenie AJAX do domu? To samo, dostaniesz ostrzeżenie<h1>Hello world, welcome to my awesome site</h1> .

Innymi słowy - nie ma nic nowego w połączeniach AJAX. Są po prostu sposobem na to, aby użytkownik mógł uzyskać dane i informacje bez opuszczania strony, a to zapewnia płynny i bardzo schludny projekt witryny. Kilka wskazówek, które należy wziąć pod uwagę:

  1. Dowiedz się jQuery . Nie mogę tego wystarczająco podkreślić. Musisz trochę to zrozumieć, aby wiedzieć, jak obsługiwać otrzymywane dane. Musisz także zrozumieć podstawową składnię JavaScript (niedaleko Pythona, przyzwyczaisz się). Zdecydowanie polecam samouczki wideo Envato dla jQuery , są świetne i wprowadzą cię na właściwą ścieżkę.
  2. Kiedy używać JSON? . Zobaczysz wiele przykładów, w których dane wysyłane przez widoki Django są w JSON. Nie wdałem się w to szczegółowo, ponieważ nie jest ważne, jak to zrobić (jest mnóstwo wyjaśnień) i dużo ważniejsze, kiedy . Odpowiedź brzmi: dane JSON to dane serializowane. To znaczy dane, którymi możesz manipulować. Jak wspomniałem, wywołanie AJAX pobierze odpowiedź tak, jakby użytkownik zrobił to sam. Teraz powiedz, że nie chcesz zadzierać z całym plikiem HTML, a zamiast tego chcesz wysyłać dane (być może listę obiektów). JSON jest do tego dobry, ponieważ wysyła go jako obiekt (dane JSON wyglądają jak słownik Pythona), a następnie możesz iterować nad nim lub zrobić coś innego, co eliminuje potrzebę przesiewania przez bezużyteczny HTML.
  3. Dodaj to na końcu . Kiedy budujesz aplikację internetową i chcesz wdrożyć AJAX - zrób sobie przysługę. Po pierwsze, zbuduj całą aplikację całkowicie pozbawioną AJAX. Sprawdź, czy wszystko działa. Wtedy i tylko wtedy zacznij pisać wywołania AJAX. To dobry proces, który pomaga ci się dużo nauczyć.
  4. Użyj narzędzi programistycznych Chrome . Ponieważ wywołania AJAX są wykonywane w tle, czasami bardzo trudno jest je debugować. Powinieneś użyć narzędzi programistycznych chrome (lub podobnych narzędzi, takich jak firebug) i console.logrzeczy do debugowania. Nie wyjaśnię szczegółowo, po prostu google i dowiedz się o tym. Byłoby ci bardzo pomocne.
  5. Świadomość CSRF . Na koniec pamiętaj, że żądania postów w Django wymagają csrf_token. W przypadku połączeń AJAX wiele razy chcesz wysyłać dane bez odświeżania strony. Prawdopodobnie napotkasz jakieś problemy, zanim w końcu to pamiętasz - poczekaj, zapomniałeś wysłać csrf_token. Jest to znana blokada dla początkujących w integracji AJAX-Django, ale kiedy nauczysz się, jak sprawić, by gra była przyjemna, to proste.

To wszystko, co przychodzi mi do głowy. To rozległy temat, ale tak, prawdopodobnie nie ma wystarczająco wielu przykładów. Po prostu pracuj tam, powoli, w końcu to dostaniesz.

yuvi
źródło
1
Dzięki. Po prostu byłem tam, gdzie jesteś, znam to uczucie. Jeśli chodzi o rozmowy - ogólnie tak, ale nie teraz (także, w przypadku konkretnych pytań masz ... no cóż ... całość SO).
yuvi
2
PS Łączone przeze mnie filmy mają cały tydzień poświęcony AJAX. Poważnie, przejrzyj je. Są fantastyczne
yuvi
Dzięki za to @yuvi! Zadaję sobie to samo pytanie o AJAX. Co więcej, nie jestem pewien, kiedy muszę używać AJAX, czy nie. Na przykład rozumiem, że będę potrzebować trochę Javascript do obsługi formularzy modalnych Bootstrap, ale nie rozumiem, czy jest to związane z AJAX, czy nie. A tak na poważnie, muszę nauczyć się całej Jquery, żeby pojawił się na mojej stronie wyskakujące okienko ... Nie widzę zwrotu z inwestycji :( Czy jest jakaś prostsza alternatywa? :( Jeszcze raz dziękuję za odpowiedź.
David D.
5
@DavidW. Cześć David, cieszę się, że moja odpowiedź ci pomogła. AJAX to technika, którą można wykonać za pomocą prostego javascript, ale może stać się bardzo skomplikowana. jQuery ma po prostu skróty, które znacznie ułatwiają. Nie ma to nic wspólnego z modalnością Bootstrap (możesz pobrać formularze za pomocą AJAX, jeśli chcesz, ale poza tym nie ma to związku). W każdym razie, zdecydowanie sugeruję, abyś powoli starał się znaleźć właściwą drogę. jQuery jest obecnie ważny i bardzo podstawowy, więc warto tam zainwestować. Gdy trafisz na blokadę, przyjdź do SO i zapytaj (nie w komentarzach do pytania, na które już udzielono odpowiedzi, otwórz nowe). Powodzenia!
yuvi
W odniesieniu do Twojej wzmianki o tym csrf_token, czy możemy obejść tę metodę? Gdybyśmy mieli przykładową funkcję, ajaxCall()moglibyśmy po prostu użyć tradycyjnej metody czegoś takiego <form onsubmit='ajaxCall();return false;'>, prawda?
ytpillai
22

Oprócz doskonałej odpowiedzi yuvi, chciałbym dodać mały konkretny przykład, jak sobie z tym poradzić w Django (poza wszelkimi używanymi js). W przykładzie użyto AjaxableResponseMixini przyjęto model autora.

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']

Źródło: Dokumentacja Django, Obsługa formularzy z widokami klasowymi

Link do wersji 1.6 Django nie jest już dostępny, zaktualizowany do wersji 1.11

Wtower
źródło
14

Piszę to, ponieważ przyjęta odpowiedź jest dość stara, wymaga odświeżenia.

W ten sposób zintegrowałbym Ajax z Django w 2019 roku :) I weźmy prawdziwy przykład tego, kiedy będziemy potrzebować Ajax: -

Powiedzmy, że mam model z zarejestrowanymi nazwami użytkowników i przy pomocy Ajax chcę wiedzieć, czy dana nazwa użytkownika istnieje.

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)

Również render_to_response, który jest przestarzały i został zastąpiony przez render, a od Django 1.7 i później zamiast HttpResponse używamy JsonResponse do odpowiedzi ajax. Ponieważ jest wyposażony w koder JSON, więc nie trzeba serializować danych przed zwróceniem obiektu odpowiedzi, ale HttpResponsenie jest on przestarzały.

Ahtisham
źródło
8

Prosty i ładny. Nie musisz zmieniać swoich poglądów. Bjax obsługuje wszystkie Twoje linki. Sprawdź to: Bjax

Stosowanie:

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

Na koniec dołącz to do HEAD swojego html:

$('a').bjax();

Aby uzyskać więcej ustawień, sprawdź demo tutaj: Bjax Demo

wytrzymać
źródło
18
Cześć, szybka uwaga - chcę doradzić każdemu, kto dopiero zaczyna się uczyć Django i \ lub AJAX - nie używaj tego. Niczego się nie nauczysz. Zachowaj go w ulubionych i samodzielnie twórz żądania AJAX. Wróć i skorzystaj z Bjax, gdy już wiesz, jak działa w tle. To nie jest tak, jakby kazać ludziom uczyć się asemblera w celu kodowania - nie musisz budować swoich żądań AJAX z czystym JS, tylko jQuery, ponieważ jeśli kiedykolwiek chcesz być profesjonalistą, to minimalna podstawowa wiedza, którą będziesz trzeba mieć. Pozdrawiam
yuvi,
5

AJAX to najlepszy sposób wykonywania zadań asynchronicznych. Wykonywanie połączeń asynchronicznych jest czymś powszechnym w każdym budynku witryny. Podamy krótki przykład, aby dowiedzieć się, jak możemy wdrożyć AJAX w Django. Musimy użyć jQuery, aby napisać mniej javascript.

To jest przykład kontaktu , który jest najprostszym przykładem, którego używam do wyjaśnienia podstaw AJAX i jego implementacji w Django. W tym przykładzie będziemy składać żądanie POST. Podążam za przykładem tego postu: https://djangopy.org/learn/step-up-guide-to-implement-ajax-in-django

models.py

Najpierw stwórzmy model kontaktu, zawierający podstawowe szczegóły.

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

Utwórz formularz dla powyższego modelu.

from django import forms
from .models import Contact

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

views.py

Widoki wyglądają podobnie do podstawowego widoku tworzenia opartego na funkcjach, ale zamiast wracać z renderowaniem, używamy odpowiedzi 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

Utwórzmy trasę powyższego widoku.

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'),
]

szablon

Przechodząc do sekcji frontonu, renderuj formularz utworzony powyżej otaczającego tagu formularza wraz z csrf_token i przyciskiem Prześlij. Pamiętaj, że zawarliśmy bibliotekę 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

Porozmawiajmy teraz o części javascript, na formularzu prześlijmy składamy zapytanie ajaxowe typu POST, pobieramy dane formularza i wysyłamy na stronę serwera.

$("#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)
            }
        });
   });

To tylko podstawowy przykład, aby zacząć korzystać z AJAX z django, jeśli chcesz nurkować z kilkoma innymi przykładami, możesz przejść przez ten artykuł: https://djangopy.org/learn/step-up-guide-to- implement-ajax-in-django

Jai Singhal
źródło
2

Próbowałem użyć AjaxableResponseMixin w moim projekcie, ale otrzymałem następujący komunikat o błędzie:

Nieprawidłowo skonfigurowany: brak adresu URL do przekierowania. Podaj adres URL lub zdefiniuj metodę get_absolute_url w modelu.

Wynika to z faktu, że CreateView zwróci odpowiedź przekierowania zamiast zwracać odpowiedź HttpResponse podczas wysyłania żądania JSON do przeglądarki. Wprowadziłem więc kilka zmian w AjaxableResponseMixin. Jeśli żądanie jest żądaniem ajax, nie wywoła super.form_validmetody, wystarczy wywołać form.save()bezpośrednio.

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
Enix
źródło
0

Kiedy używamy 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
----------------------------

Jeśli chcesz zachować stare dane, możesz to zrobić bez Ajax. (Strona zostanie odświeżona)

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.

Lub możesz zrobić z Ajax (Strona nie zostanie odświeżona)

--------------------------
<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)
---------------------------------

Jeśli używasz Ajax, musisz wykonać następujące czynności:

  1. Inicjowanie strony HTML za pomocą adresu URL1 (zazwyczaj inicjujemy stronę według szablonu Django). A następnie serwer wysyła klientowi stronę HTML.
  2. Użyj Ajax do komunikacji z serwerem za pomocą URL2. A następnie serwer wysyła do klienta strukturę danych.

Django różni się od Ajax. Przyczyna tego jest następująca:

  • Rzecz do klienta jest inna. Przypadkiem Django jest strona HTML. Przypadkiem Ajax jest struktura danych. 
  • Django jest dobry w tworzeniu czegoś, ale może stworzyć tylko raz, nie może niczego zmienić. Django jest jak anime, składa się z wielu zdjęć. Dla kontrastu, Ajax nie jest dobry w tworzeniu czegoś, ale jest dobry w zmianie czegoś w istniejącej stronie HTML.

Moim zdaniem, jeśli chcesz używać wszędzie ajax. kiedy musisz najpierw zainicjować stronę danymi, możesz użyć Django z Ajax. Ale w niektórych przypadkach potrzebujesz tylko strony statycznej bez niczego z serwera, nie musisz używać szablonu Django.

Jeśli nie uważasz, że Ajax jest najlepszą praktyką. możesz użyć szablonu Django, aby zrobić wszystko, na przykład anime.

(Mój angielski nie jest dobry)

Kyakya
źródło