Django-tastypie: Verschiedene Felder f√ľr SHOW- und INDEX-Aktionen

Erstellt am 25. Okt. 2010  ¬∑  40Kommentare  ¬∑  Quelle: django-tastypie/django-tastypie

Hallo zusammen, ist es m√∂glich, je nach Aktion unterschiedliche Felder f√ľr Ressourcen anzuzeigen.

Ich möchte, dass die Indexaktion nicht mit allen has_many-Feldern belastet wird, die die Ressource enthält.

Zum Beispiel m√∂chte ich in der Indexansicht des Autors nur seinen Namen zur√ľckgeben, aber f√ľr die Show-Aktion m√∂chte ich alle B√ľcherressourcen einschlie√üen.

Danke,
Bojan

documentation feature

Hilfreichster Kommentar

Eine einfache Problemumgehung, die ich verwende, besteht darin, die Methoden get_detail & get_list zu √ľberschreiben, um solche Felder zu bearbeiten.
Dies spart den Aufwand f√ľr das tats√§chliche Abrufen der Daten f√ľr das Feld und das anschlie√üende L√∂schen aus dem Bundle, aber ich bin mir nicht sicher, ob diese Methode threadsicher ist, da die Resource-Objekte anscheinend nicht bei jedem API-Aufruf erstellt werden.
Es wäre toll, wenn sich jemand dazu äußern könnte.

Hier ist der Code:

class ArticleResource(BaseModelResource):
    owner = fields.ToOneField(UserResource, 'owner', full=True)

    class Meta:
        resource_name = "articles"

    def get_list(self, request, **kwargs):
        self.fields.pop("comments", None)
        return super(ArticleResource, self).get_list(request, **kwargs)

    def get_detail(self, request, **kwargs):
        self.fields["comments"] = fields.ToManyField(CommentResource, 'comments', full=True)
        return super(ArticleResource, self).get_detail(request, **kwargs)

Alle 40 Kommentare

+1
Ich hoffe sehr auf dieses Feature: "Detailfeld" und "Listenfeld" können getrennt werden

+1 (√ľber Duplikat bei #44)

Es scheint mir, dass es zwei Dinge gibt, die das Abrufen einer Teilmenge von Daten in Indexaktionen erleichtern könnten:

  1. Lassen Sie full_dehydrate verschiedene Felder f√ľr Index- und Get-Methoden verwenden. Vielleicht sowas wie:

Meta:
index_exclude_fields = ['some_m2m_field']

Dies w√ľrde es uns erm√∂glichen, einige DB-Abfragen zu speichern.

  1. √úbergeben Sie einen zus√§tzlichen 'Methode'-Parameter, um zu dehydrieren. Dies w√ľrde eine Anpassung des Bundles erm√∂glichen, z. B. das √úberspringen einiger Felder, die im Index nicht ben√∂tigt werden, und wir m√∂chten etwas Bandbreite sparen.

Ich habe nicht bewertet, 1. w√ľrde Auswirkungen auf das Caching haben.
Was denken Sie?

Auch in #48 getäuscht, aber jede Ausgabe hat lohnende Aspekte.

Ich wollte diese Funktion abbrechen, wenn ich k√∂nnte, aber ich bin weit unterlegen. Es muss sowieso f√ľr eine bessere Dateiunterst√ľtzung da sein, also muss es behoben werden. Werde hier 1.0 anvisieren.

Nachdem ich meinen Anwendungsfall daf√ľr etwas genauer untersucht habe, m√∂chte ich vorschlagen, dass es flexibler implementiert wird als nur Show-/Listenansichten. Was ich wirklich tun muss, ist ein Abfragestring-Flag wie folgt:

&shape=[voll|einfach|keine]

und lassen Sie die Ausgabe den ausgew√§hlten Detaillierungsgrad des Benutzers widerspiegeln. Ich habe nach einer M√∂glichkeit gesucht, dies zu hacken, aber da die Felder beim Erstellen der ModelResource-Klasse eingeschlossen/ausgeschlossen werden, konnte ich keine M√∂glichkeit finden, die sp√§ter im Antwortzyklus verf√ľgbaren Elemente zu √§ndern. Au√üerdem ist das Anforderungsobjekt in den Prozessschritten, in denen ich eine solche Feststellung treffen m√∂chte, nicht verf√ľgbar.

+1

Ich werde diesen Gedanken hier zuerst erw√§hnen, da er f√ľr dieses Problem relevant zu sein scheint, aber er muss m√∂glicherweise in seinen eigenen ausgegliedert werden.

Wenn ein Mechanismus zum Anzeigen verschiedener Felder entwickelt wird, w√§re es n√ľtzlich, wenn dieser auch in die Authentifizierung integriert werden k√∂nnte. In der Lage zu sein, mehr/weniger Felder verf√ľgbar zu machen, h√§ngt von den Berechtigungen des Benutzers ab, w√§re sehr m√§chtig. Falls dies bereits m√∂glich ist, konnte ich keine Erw√§hnung finden.

+1

+1

+1

+1

+1

+1

+1

Ich w√ľrde erwarten, in der Lage zu sein, die angezeigten Felder (mit Feldern oder Ausschl√ľssen) zus√§tzlich zur Liste / zum Detail nach einer Methode (POST, PUT, GET) zu steuern.

Hier ist eine Problemumgehung, siehe das Beispiel unten: Sie schlie√üen nichts aus dem Ressourcenmodell des urspr√ľnglichen Modells (UserResource im Beispiel) aus, damit es in seiner Indexansicht vollst√§ndig angezeigt wird. Sie m√ľssen in die dehydrate-Methode der modelresource gehen, die Ihr Untermodell enth√§lt (die BlogPostResource enth√§lt den Autor) und einfach die Elemente des Bundles l√∂schen.

Beispiel:

class BlogPostResource(ModelResource):
     author = fields.ForeignKey(UserResource, 'author', full=True)
     ....
     class Meta:
         ...

def dehydrate(self, bundle):
         del bundle.data['author'].data['field_you_dont_wanna_show_here']
         del bundle.data['author'].data['field_you_dont_wanna_show_here']
         return bundle

Wenn Sie also die Benutzer auflisten möchten, erhalten Sie immer noch alle Felder, aber wenn Sie Blogposts auflisten, können Sie beispielsweise nur den Vor- und Nachnamen des Autors abrufen.

Was denken Sie?

Beispiel f√ľr eine sehr, sehr schmutzige Problemumgehung: Zeigt keine Projektfelder in list_view an, aber in detail_view, ohne auf die Ressource selbst zugreifen zu m√ľssen, die URL selbst ohne Hardcoding zu erhalten sollte m√∂glich sein, hatte aber keine Zeit, sie auszuchecken :

class CompanyResource(ModelResource):
       """
       Tastypie resource for Company
      """
       projects = fields.ToManyField('api.resources.ProjectResource',
                                  'projects',full=True)
       class Meta:
           queryset = Company.objects.all()
           resource_name = 'companies'

       def dehydrate(self, bundle):
           if bundle.request.path == "/api/v1/companies/":
               del bundle.data['projects']
           return bundle

+1

+1

+1

Ich werde auch an Bord springen , es wäre schön, einen Zug zu haben, aber was durchzubringen . Ich habe es leicht modifiziert, um etwas dynamischer zu sein.

    def dehydrate(self, bundle):
        if self.get_resource_uri(bundle) == bundle.request.path:
            print "Detail"

        if self.get_resource_uri(bundle) != bundle.request.path:
            print "Not Detail - Could be list or reverse relationship."

        return bundle

Also habe ich mir etwas mehr Gedanken gemacht und mir etwas einfallen lassen, das mir ziemlich nahe kommt, das zu tun, wonach nach gesucht hat.

Angenommen, wir möchten das @ashwoods nur anzeigen, wenn es sich um eine Detailantwort handelt:

class CompanyResource(ModelResource):
    """
    Tastypie resource for Company
    """

    class Meta:
        queryset = Company.objects.all()
        resource_name = 'companies'
        additional_detail_fields = {'projects': fields.ToManyField('api.resources.ProjectResource', 'projects',full=True)}

    def dehydrate(self, bundle):
        # detect if detail
        if self.get_resource_uri(bundle) == bundle.request.path:
            # detail detected, include additional fields
            bundle = self.detail_dehydrate(bundle)

        return bundle

    # detail_dehydrate is basically full_dehydrate
    # except we'll loop over the additional_detail_fields
    # and we won't want to do the dehydrate(bundle) at the end
    def detail_dehydrate(self, bundle):
        """
        Given a bundle with an object instance, extract the information from it
        to populate the resource.
        """
        # Dehydrate each field.
        # loop over additional_detail_fields instead
        #for field_name, field_object in self.fields.items():
        for field_name, field_object in self._meta.additional_detail_fields.items():
            # A touch leaky but it makes URI resolution work.
            if getattr(field_object, 'dehydrated_type', None) == 'related':
                field_object.api_name = self._meta.api_name
                field_object.resource_name = self._meta.resource_name

            bundle.data[field_name] = field_object.dehydrate(bundle)

            # Check for an optional method to do further dehydration.
            method = getattr(self, "dehydrate_%s" % field_name, None)

            if method:
                bundle.data[field_name] = method(bundle)

        # dehydrating the bundle will create an infinite loop
        #bundle = self.dehydrate(bundle)
        return bundle

+1, vorerst mit Fix von

+1

+1

Teilimplementierung in # 526, ich bin mir nicht sicher, ob ich von allem verkauft bin und es fehlen Tests/Dokumente.

Habe gerade dieses Ticket gesehen ... und auch wie der oben von Onyxfish erwähnte "Shape" -Ansatz ...

Dachte, meine Lösung in #526 sei etwas eingeschränkt, falls die Leute in anderen Fällen andere "Formen" wollten ...

zu den Vorschlägen, Felder nach dem Entwässern zu entfernen ... mein einziger Grund ist es, die Berechnung der Werte von vornherein zu vermeiden.

Die Idee f√ľr den detail_dehydrate-Hook, um das bedingte Hinzuf√ľgen weiterer Details zu erm√∂glichen, gef√§llt mir jedoch.

Es sieht so aus, als w√§ren zwei m√∂gliche Implementierungen verf√ľgbar, die sowohl Tests als auch Dokumente enthalten. Ich habe eine in #569 geschrieben und #538 f√ľhrt auch eine √§hnliche Funktionalit√§t durch (#538 erm√∂glicht etwas mehr Flexibilit√§t, da use_in ein Callable sein kann). Meine Implementierung f√ľgt meta Attribute hinzu, um diese Funktionalit√§t zu steuern (die mit dem aktuellen fields Attribut √ľbereinstimmt), w√§hrend #538 ein Attribut zu Feldern hinzuf√ľgt. Beides scheint g√ľltig zu sein, nur eine Designentscheidung, in welche Richtung es gehen soll. Das Hinzuf√ľgen zum Meta erscheint mir konsistent und ist einfacher zu verwenden, da einige Felder automatisch generiert werden k√∂nnen und das √Ąndern ihrer Initialisierungsparameter m√∂glicherweise nicht m√∂glich ist. Eine andere Alternative w√§re, beide Pull-Requests zu kombinieren und zuzulassen, dass der Parameter use_in basierend auf dem Attribut meta automatisch gesetzt wird. Dies scheint jedoch die API komplexer zu machen als n√∂tig. Danke an @issackelly f√ľr den Hinweis auf entsprechende Pull Requests.

[einzustimmen, da ich die urspr√ľngliche Ursache f√ľr #538 war, es ist eine Bereinigung meiner #526]
Macht sehr viel Sinn ... der Meta-Ansatz w√ľrde in der Tat mit der Ausschlussliste f√ľr ModelResource usw.

Wie ich in einem anderen Ticket sagte, w√§re eine "einfache" L√∂sung wie diese IMHO f√ľr ein 1.0-Release ausreichend... .

@funkybob Einverstanden, sicherlich wäre die komplexere Lösung von Clientseite aus hilfreich, aber es wäre schön, diese Funktionalität so schnell wie möglich aufzunehmen, damit sie vor der Veröffentlichung von 1.0 verwendet werden kann.

Ich verwende die PR tats√§chlich in einer Produktionsanwendung, und ich mag die Flexibilit√§t des R√ľckrufs von #538 wirklich. Ich habe einige Anwendungsf√§lle, in denen ich eine Ressource zur Laufzeit basierend auf der Berechtigung ausblenden muss.

Das wäre mir mit #569 nicht möglich

Hallo, irgendwelche Neuigkeiten? Diese PR macht das Leben so einfacher, danke!

Geh mit Hack von @dericcrago

+1

Eine einfache Problemumgehung, die ich verwende, besteht darin, die Methoden get_detail & get_list zu √ľberschreiben, um solche Felder zu bearbeiten.
Dies spart den Aufwand f√ľr das tats√§chliche Abrufen der Daten f√ľr das Feld und das anschlie√üende L√∂schen aus dem Bundle, aber ich bin mir nicht sicher, ob diese Methode threadsicher ist, da die Resource-Objekte anscheinend nicht bei jedem API-Aufruf erstellt werden.
Es wäre toll, wenn sich jemand dazu äußern könnte.

Hier ist der Code:

class ArticleResource(BaseModelResource):
    owner = fields.ToOneField(UserResource, 'owner', full=True)

    class Meta:
        resource_name = "articles"

    def get_list(self, request, **kwargs):
        self.fields.pop("comments", None)
        return super(ArticleResource, self).get_list(request, **kwargs)

    def get_detail(self, request, **kwargs):
        self.fields["comments"] = fields.ToManyField(CommentResource, 'comments', full=True)
        return super(ArticleResource, self).get_detail(request, **kwargs)

+1

Eine andere Problemumgehung besteht darin, unterschiedliche Ressourcen f√ľr Detail- und Listenansichten bereitzustellen:

from tastypie.resources import ModelResource
from django.contrib.auth.models import User

# detail will show everything except password
class UserResourceDetail(ModelResource):
    class Meta:
        queryset = User.objects.all()
    excludes = ('password',)
    resource_name = 'user'

# list will only show username & date_joined (and exclude password)
class UserResource(UserResourceDetail):
    class Meta(UserResourceDetail.Meta):
        fields = ('username', 'date_joined')
    get_detail = UserResourceDetail().get_detail

# ... register & use UserResource

+1

+1 f√ľr @dnozay-Problemumgehung

+1 @dnozay , toll

Beachten Sie, dass Sie Folgendes hinzuf√ľgen m√ľssen, nachdem UserResource definiert wurde, damit get_resource_uri korrekt mit der Benutzerdetailansicht funktioniert.

UserResourceDetail.get_resource_uri = UserResource().get_resource_uri

Andernfalls ist resource_uri in allen Detailantworten leer.

Möglicherweise verwandt: #1265

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen