2011-10-19 5 views
8

Sto pianificando un sito con Django e Tastypie per l'API REST e Sto attraversando un periodo difficile per comprendere il modo "giusto" di includere le risorse secondarie in un reso risorsa.Inclusione di risorse secondarie in un'API di Django Tastypie

Come sandbox, ho creato una piccola app con un modello Ticket e un modello TicketComment , in cui i commenti appartengono a un ticket. Ho esaminato la ricetta di Tastypie Cookbook su risorse annidate (http://django-tastypie.readthedocs.org/en/latest/cookbook.html#nested-resources), ma ho difficoltà a capire perché dovrei Fai quello. Il codice sottostante utilizza django.forms.models.model_to_dict() per ottenere i commenti nel ticket, ma sto pensando che qui ci sia un "trucco" qui da qualche parte.

C'è una ragione per cui non dovrei fare quello che sto facendo ora? Inoltre, esiste uno schema di sensazioni più pulite di questo tipo rispetto a quello elencato nel ricettario?

I modelli sono i seguenti:

# tickets/models.py 

from django.db import models 

class Ticket(models.Model): 
    title = models.CharField(max_length=200) 
    create_ts = models.DateTimeField(auto_now_add=True) 
    submitter_email = models.EmailField() 
    PRIORITY_CHOICES = (
     ('H', 'High'), 
     ('M', 'Medium'), 
     ('L', 'Low'),) 
    priority = models.CharField(max_length=1, choices=PRIORITY_CHOICES) 
    description = models.TextField() 
    STATUS_CHOICES = (
     ('NEW', 'New & Unclaimed'), 
     ('WIP', 'Work In Progress'), 
     ('RES', 'Resolved'), 
     ('CLS', 'Closed'),) 
    status = models.CharField(max_length=3, choices=STATUS_CHOICES) 

    def __unicode__(self): 
     return "<Ticket:%d:%s>" % (self.id, self.title,) 

class TicketComment(models.Model): 
    ticket = models.ForeignKey(Ticket) 
    comment_ts = models.DateTimeField(auto_now_add=True) 
    commenter_email = models.EmailField() 
    comment = models.TextField() 

    def __unicode__(self): 
     return "<TicketComment:%d:%d>" % (self.ticket.id, self.id,) 

risorse sono i seguenti:

# tickets/api.py 

from tastypie import fields 
from tastypie.resources import ModelResource 
from tickets.models import Ticket, TicketComment 
from django.forms.models import model_to_dict 

class TicketResource(ModelResource): 

    class Meta: 
     queryset = Ticket.objects.all() 
     resource_name = 'ticket' 

    def dehydrate(self, bundle): 
     comments = TicketComment.objects.filter(ticket=bundle.data['id']) 
     bundle.data['comments'] = [model_to_dict(c) for c in comments] 
     return bundle 

class TicketCommentResource(ModelResource): 
    ticket = fields.ForeignKey(TicketResource, 'ticket') 

    class Meta: 
     queryset = TicketComment.objects.all() 
     resource_name = 'comment' 

uscita è la seguente:

{ 
    comments: [ 
     { 
      comment: "This is the first comment.", 
      commenter_email: "[email protected]", 
      id: 1, 
      ticket: 1 
     }, 
     { 
      comment: "This is the second comment.", 
      commenter_email: "[email protected]", 
      id: 2, 
      ticket: 1 
     } 
    ], 
    create_ts: "2011-10-17T15:55:11.372000", 
    description: "This is the first ticket.", 
    id: "1", 
    priority: "M", 
    resource_uri: "/api/v1/ticket/1/", 
    status: "NEW", 
    submitter_email: "[email protected]", 
    title: "First Ticket" 
} 

risposta

14
+0

Grazie, questo ha molto più senso, tuttavia tutto quello che sto ottenendo è l'URL dei commenti dei bambini. Se voglio invece le risorse serializzate, c'è un modo pulito per ottenerle? – Doug

+9

utilizza l'argomento = true nella tua dichiarazione –

+0

Perfetto, esattamente quello che volevo. Grazie! – Doug

1

Puoi pubblicare la tua soluzione?

Ho gli stessi casi/modelli di utilizzo (una relazione di parentela esterna stabilita nella "tabella figlio" che rimanda alla tabella padre) ma non può risolverlo.

La soluzione che ho visto è quello di aggiungere questa linea al vostro TicketResource un livello di classe non all'interno meta sottoclasse:

comments = fields.ToManyField('TicketCommentResource', 'ticket', full=True) 

poi eventualmente aggiungi questo a TicketCommentResource, ancora una volta a livello di classe:

event = fields.ForeignKey('TicketResource', 'event') 

Ma ottengo sempre l'errore che la mia risorsa oggetto principale (nell'esempio TicketResource) non ha l'attributo 'ticket' che è il secondo termine inviato a ToManyField.

Ho provato a giocare molto ma non riesco a ottenere la combinazione vincente. La soluzione che hai originariamente pubblicato funziona ma come tu stesso hai sottolineato non è l'ideale.

Grazie!

+0

Volevo aggiungere questo come commento ma non ha avuto l'opzione. –