2009-09-29 9 views
5

L'altro giorno ho scritto alcuni AJAX per un'app Django su cui ho lavorato.un modo migliore per fare ajax in django

Vengo da Ruby on Rails, quindi non ho fatto molto in termini di raw JS.

Quindi, sulla base di Rails' parziali, ho qualcosa di simile a quanto segue in una sorta di pseudocodice, non sudare i dettagli:

1) la funzione JS usando Ajax.Updater del prototipo ('tablediv' essere l'id del tavolo ho voluto aggiornare Ajaxily, e URL che punta alla corretta visualizzazione Django)

function updateTable(){ 
     new Ajax.Updater('tablediv',url {params: params....etc 

2) vista Django che ha ottenuto nuovi dati per compilare la tabella con:

def ajaxTable 
    objects = Objects.object.all... 
    return render_to_response('ajaxtable.html',objects) 

3) ajaxtable.html era solo una specie di Rails "parziale" in modo sostanzialmente un tavolo w/o <table></table> ...:

<th>{{object.data}}</th> 
    <td>{{object.moredata}}</td> 

così alla mia domanda effettiva:

Questo sembrava hacky a me , Ho quasi buttato tutto insieme dopo essermi stancato di cercare online ciò che volevo.

È così che è fatto? Funziona bene, non so abbastanza per saperlo, sai?

risposta

1

Che cosa sembra esattamente un hacker? Sembra un modo perfettamente valido per fare qualcosa.

Immagino che un'alternativa sia serialising a json e la rinvia a uno snippet javascript templating.

+0

Questo è quello con cui avevo giocato, ma al tempo non conoscevo il javascript che conosco, quindi invia gli oggetti come JSON, crea i valori javascript dell'oggetto letterali e poi tablediv.innerHTML = foo ? – Joel

+0

JSON * è * un oggetto letterale quindi la cosa bella di usarlo in javascript è che non devi fare nulla con esso per usarlo effettivamente una volta che ce l'hai. Mi piace usare JSON in congiunzione con il sistema di template che ho linkato sopra (jquery, non prototype, sorry) perché puoi semplicemente passare il JSON restituito direttamente al template che hai configurato e funzionerà. – Steerpike

2

Non importa quello, si sta andando ad avere bisogno di almeno due cose:

  1. il codice JavaScript per effettuare la chiamata (si dispone di questo) codice lato

  2. Server per gestire la richiesta (questa è la tua vista e url-config)

Non c'è assolutamente nulla di "hacky" a riguardo.

La terza cosa, il file modello, è facoltativa, ma in genere è una buona pratica. Vuoi separare il tuo markup dal codice, per molte ragioni.

Quindi penso che tu abbia avuto l'idea giusta. Proseguire.

+0

nice, grazie per la risposta, ho finito il progetto e sono andato avanti, ma da allora mi ha infastidito (quando sono nel mezzo di qualcosa che non posso smettere di chiedere su un forum o stack overflow..Io 't hanno la pazienza :), bene sapere che il mio istinto non sono completamente ridiculus – Joel

5

Dipende un po 'da quello che vuoi, penso. Ajax è una gamma piuttosto ampia di scenari, da Google Maps a un varys con completamento automatico semplice, estremamente complesso e l'approccio migliore.

Tuttavia, ci sono alcune cose utili che puoi fare in questo modo.

1) livello di modello

Assicurarsi di avere "django.core.context_processors.request" nel vostro ambiente TEMPLATE_CONTEXT_PROCESSORS.Quindi puoi farlo;

{% if not request.is_ajax %} 
<html> 
    <head> 
    ... 
    </head> 
    <body> 
    ... 
{% endif %} 
actual content 
{% if not request.is_ajax %} 
</body> 
</html> 
{% endif %} 

Fondamentalmente poi dire questa pagina è/test/si può fare una richiesta del browser e ottenere l'intero contenuto o una richiesta tramite JavaScript e solo ottenere il contenuto. C'è un post di blog da qualche parte che spiega questo in modo più dettagliato ma non riesco a trovarlo al momento.

2) Dal punto di vista

Nel modello ci sono solo accedendo ad un oggetto di richiesta nel modello. Nella vista puoi fare cose molto simili.

def my_view(request): 
    if requst.is_ajax(): 
     # handle for Ajax requests 

    # otherwise handle 'normal' requests 
    return HttpResponse('Hello world') 

I metodi di cui sopra in realtà non lo fanno in modo diverso di te, ma ti permettono di riutilizzare i punti di vista e scrivete po 'più conciso. Non direi realmente che cosa stai facendo sia sbagliato o hacky ma potresti scriverlo per renderlo più conciso e riutilizzare i modelli e le visualizzazioni.

dire ad esempio che si può avere solo un modello e se è una richiesta Ajax restituire solo la sezione che dovrà essere aggiornata. Nel tuo caso sarebbero le viste delle tabelle.

+0

Questo sembra davvero intelligente, proveniente da utilizzando rubino incastonato che piace a me ... forse troppo intelligente ... – Joel

+0

haha ​​no html nei commenti ... – Joel

+0

troppo intelligente? Mi piace davvero molto. Puoi completamente Ajaxify grandi bit di un sito web rapidamente, purtroppo non c'è modo di avere più di un 'blocco ajax' per modello ... hmm Mi chiedo come si potrebbe fare. –

4

Sono abbastanza in ritardo, ma voglio documentare come combinare e adattare le soluzioni presentate da d0ugal in un modo, che risolverà un codice modello molto più pulito.

Ho un modello che rappresenta le persone di contatto.

L'(generica) al fine di ottenere uno ContactPerson assomiglia a questo:

def contcactperson_detail_view(request, name): 
    try: 
     person = ContactPerson.objects.get(slug=name) 
    except: 
     raise Http404 
    if request.is_ajax(): 
     return contcactperson_detail_view_ajax(request, person) 
    return list_detail.object_detail(
      request, 
      queryset = ContactPerson.objects.all(), 
      object_id = person.id, 
      template_object_name = "contactperson", 
     ) 

@render_to('cms/contactperson_detail_ajax.html')  
def contcactperson_detail_view_ajax(request, person): 
    return {'contactperson':person, 'is_ajax':True} 

Il modello per rendere l'idea che gestisce uno ContactPerson si chiama contcactperson_detail_view.html:

{% extends "index.html" %} 
{% block textpane %} 

<h1 id="mainheader">{{ contactperson.first_name }} {{ contactperson.family_name }} </h1> 
<div class="indentation">&nbsp;</div> 
{% include 'cms/contactperson_detail_photo.html' %}                           
<div id="text_pane"> 

{% include 'cms/contactperson_detail_textpane.html' %} 
</div> 
{% endblock %} 

Esso comprende due sotto- modelli

contactperson_detail_textpane.html 


<p>{{ contactperson.description }}</p> 
<ul> 
    <li> 
     <dl> 
      <dt>Email</dt> 
      <dd> 
       {{ contactperson.mail }} 
      </dd> 
     </dl> 
    </li> 
    <li> 
     <dl> 
      <dt>Contact Person for</dt> 
      <dd> 
       <ul> 
       {% for c in contactperson.categories.all %} 
        <li><a href="{% url category-view c.slug %}">{{ c }}</a></li> 
       {% endfor %} 
       </ul> 
      </dd> 
     </dl> 
    </li> 
</ul> 

e contactperson_detail_photo.html

{% with contactperson.photo.detailphoto as pic %} 
    {% with pic.url as pic_url %}  
    <div {% if not is_ajax %}id='imageContainer'{% endif %} style="float: right;padding-right:0.5em; 
            padding-bottom: 1em; padding-left:0.5em;clear:both; 
            width:{{ pic.width }}px"> 
     <div style="width:{{ pic.width}}px">      
       <img style="clear:both" src="{{ pic_url }}" alt="{{ i.name }}"/> 
     </div>                              
    </div> 
    {% endwith %} 
{% endwith %} 

questo 3 modelli verranno utilizzati, se la richiesta non è ajax.

Ma se la richiesta è ajax, contcactperson_detail_view restituirà la vista contcactperson_detail_view_ajax, che utilizza il modello contactperson_detail_ajax.html per il rendering. E questo modello si presenta così:

<h1>{{ contactperson.first_name }} {{ contactperson.family_name }}</h1> 
{% include 'cms/contactperson_detail_photo.html' %}                           
{% include 'cms/contactperson_detail_textpane.html' %} 

in modo che utilizza gli stessi sub-modelli, ma non sta estendendo nulla, quindi solo il markup necessario consegnato. Poiché la vista ajax passa a is_ajax = True nel modello, può essere utilizzata per regolare elementi secondari, come l'impostazione di attributi ID corretti.

Nessun processore di contesto o ulteriore url-conf necessario.

Infine il codice Javascript:

$("#contact_person_portlet a").click(function(event){ 
     event.preventDefault(); 
     $.ajax({ 
      type: "GET", 
      url: event.target.getAttribute('href'), 
      success: function(msg){ 
       overlay(msg); 
      } 
     }); 
    }); 

speranza che possa essere utile per alcune persone. Se è così, per favore lascia un commento!

+0

Credo che sia possibile implementare una soluzione più semplice utilizzando una singola vista e lo stesso modello per ajax/non-ajax, ma ereditando da un modello di base diverso in base a una variabile di contesto. Vedi http://stackoverflow.com/questions/4014156/django-templates-sysntax-error/4018629#4018629 per una risposta che ho dato ad un'altra domanda in quella riga –

+0

davvero molto elegante – vikingosegundo

Problemi correlati