2009-06-30 10 views
1

Ich möchte in der Lage sein, den Datensatz entsprechend den URL-Parametern unterschiedlich anzuzeigen.Exportieren von Datensätzen in verschiedenen Formaten

Meine URL sieht wie/page/{limit}/{offset}/{format}/aus.

Zum Beispiel:

/page/20/0/xml/ - subset [0:20) in xml 
/page/100/20/json/ - subset [20:100) in json 

Auch ich möchte in der Lage für csv das gleiche zu tun, Text, Excel, PDF, HTML, etc ...

ich müssen in der Lage sein zu setzen verschiedene MIME-Typen und Content-Typen für verschiedene Formate. Für XML sollte application/xhtml + xml, für csv sein - text/plain, etc ...

Im HTML-Modus möchte ich in der Lage sein, diese Daten in eine Vorlage zu übergeben (I‘ m mit Django).

Ich bin der Planung wie Set aussehen zu lassen:

dataset = { 
    "meta" : {"offset" : 15, "limit" : 10, "total" : 1000}, 
    "columns" : {"name" : "Name", "status" : "Status", "creation_date" : "Creation Date"} 
    "items" : 
     [ 
      {"name" : "John Smith", "status" : 1, "creation_date" : "2009-06-30 10:10:09"}, 
      {"name" : "Joe The Plummer", "status" : 2, "creation_date" : "2009-06-30 10:10:09"} 
     ] 
}; 

und haben folgende Ausgabe:

CSV-Ausgabe:

Name, Status, Creation Date 
John Smith, 1, 2009-06-30 10:10:09 
Joe The Plummer, 2, 2009-06-30 10:10:09 

XML-Ausgabe:

<items> 
    <item id="1"> 
     <name>John Smith</name> 
     <status>1</status> 
     <creation_date>2009-06-30 10:10:09</creation_date> 
    </item> 
    <item id="2"> 
     <name>Joe The Plummer</name> 
     <status>2</status> 
     <creation_date>2009-06-30 10:10:09</creation_date> 
    </item> 
</items> 

Also ich denke um zu implementieren ented meine eigenen Renderer für jeden Typ - wie XMLRenderer, RSSRenderer, JSONRenderer, etc ...

if format == "xml": 
    context = XMLRenderer().render(data = dataset) 

    return HttpResponse(content, mimetype="application/xhtml+xml") 
elif format == "json": 
    context = JSONRenderer().render(data = dataset) 

    return HttpResponse(content, mimetype="text/plain") 
elif format == "rss": 
    context = RSSRenderer(title="Some long title here", link="/page/10/10/rss/").render(data = dataset) 

    return HttpResponse(content, mimetype="application/xhtml+xml") 

# few more formats... 

else: 
    return render_to_response(SOME_TEMPLATE, dataset) 

richtige Ansatz ist es?

Antwort

1

Ich schlage vor, mit den Renderer auch über den MIME-Typen wissen, anstatt diese in dem Code zu mit dem Renderer nennt - besser formatspezifische Wissen an einem Ort zu konzentrieren, so dass der anrufende Code wäre

content, mimetype = renderer().render(data=dataset) 
return HttpResponse(content, mimetype=mimetype) 

auch, dies ist eine großartige Gelegenheit für das Designmuster der Registrierung (die meisten langen Bäume von If/Elif sind, aber eine, wo Sie im Wesentlichen entscheiden, welches Objekt oder Klasse zu verwenden ist perfekt! -). Also entweder Sie codieren eine dict:

format2renderer = dict(
    xml=XMLRenderer, 
    rss=RSSRenderer, 
    # ...etc... 
) 

oder vielleicht noch besser machen Renderer selbst registrieren im dict beim Start, aber das kann zu weit fortgeschritten sein/schwer zu vereinbaren. In jedem Fall, was Sie vor dem anrufenden Schnipsel haben würde ich gerade eben zitierte sein:

renderer = format2renderer.get(format) 
if renderer is not None: ... 

und wenn None können Sie Ihren Standard-Code anwenden. Ich finde Dict-Lookups und Polymorphie so viel einfacher zu pflegen und zu verbessern als wenn/elif Bäume! -)

+0

Gute Idee, Standard-Mimetype in Renderer-Klasse, danke zu haben. Aber ich bin mir nicht sicher, ob ich es beim Aufruf von render() zurückgeben soll. Ich werde die Methode get_mimetype() in meiner übergeordneten Renderer-Klasse verwenden. Zum Beispiel json_renderer = JSONRenderer(); Inhalt = json_renderer.Rendern (Daten = Datensatz); gibt HttpResponse zurück (content, mimetype = json_renderer.get_mimetype()). Ich mag diesen Weg besser, weil ich in der Zukunft Daten in Datei oder Logarithmus oder was auch immer rendern werde, also muss ich nichts über Mimetype als zweiten Rückgabeparameter von render() wissen. Vielen Dank. – zinovii

+0

Ich dachte über dict und Registry Design Muster nach und komme, dass es nicht für mich arbeiten wird. Da für einige Renderer-s ich zusätzliche Parameter im Konstruktor wie "title" und "id" für RSSRenderer übergeben muss (title = "Irgendein Titel", id = "http://example.com/bla/"), oder übergeben zu xslt für XMLRenderer (xslt = "http://example.com/bla.xslt"). Vielen Dank. – zinovii

+0

dict/registry funktioniert auch dann noch, wenn einige Renderer Parameter benötigen: einfach triple (renderer, a, kw) registrieren, wobei a und kw ein Tupel der Positionsargumente und ein dict der benannten Args sind (jeweils leer, wenn keine) Lassen Sie den None-Fall so schnell wie möglich aus und rufen Sie den Renderer auf (Format, * a, ** kw). Genauso können Sie natürlich auch functools.partial verwenden. –

0

Ja, das ist ein richtiger Ansatz.

Verwandte Themen