Django-tastypie: Bidang yang berbeda untuk tindakan SHOW dan INDEX

Dibuat pada 25 Okt 2010  ·  40Komentar  ·  Sumber: django-tastypie/django-tastypie

Hai semua, apakah mungkin untuk menampilkan bidang yang berbeda untuk sumber daya tergantung tindakan.

Alasan saya menginginkannya adalah untuk menghindari beban tindakan indeks dengan semua bidang has_many yang termasuk sumber daya.

Misalnya dalam tampilan indeks Penulis saya hanya ingin mengembalikan namanya, tetapi untuk tindakan pertunjukan saya ingin memasukkan semua sumber daya buku.

Terima kasih,
Bojan

documentation feature

Komentar yang paling membantu

Solusi sederhana yang saya gunakan adalah mengganti metode get_detail & get_list untuk mengedit bidang tersebut.
Ini menghemat overhead untuk benar-benar mengambil data untuk bidang dan kemudian menghapusnya dari bundel, tetapi saya tidak yakin apakah metode ini aman, karena sepertinya objek Resource tidak dibuat pada setiap panggilan api.
Akan sangat bagus jika seseorang dapat mengomentari ini.

Berikut kodenya:

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)

Semua 40 komentar

+1
Saya sangat berharap fitur ini: "bidang detail" dan "bidang daftar" dapat dipisahkan

+1 (melalui duplikat di #44)

Menurut saya ada dua hal yang dapat mempermudah mendapatkan subset data dalam tindakan indeks:

  1. Jadikan full_dehydrate menggunakan bidang yang berbeda untuk indeks dan dapatkan metode. Mungkin sesuatu seperti:

Meta:
index_exclude_fields = ['some_m2m_fields']

Ini akan memungkinkan kami untuk menyimpan beberapa kueri db.

  1. Lewati parameter 'metode' tambahan untuk dehidrasi. Ini akan memungkinkan kustomisasi bundel seperti melewatkan beberapa bidang yang tidak diperlukan dalam indeks dan kami ingin menghemat beberapa bandwidth.

Saya tidak mengevaluasi 1. akan berdampak pada caching.
Bagaimana menurutmu?

Juga ditipu di # 48, tetapi setiap masalah memiliki aspek yang berharga.

Saya ingin mendorong fitur ini jika saya bisa, tetapi saya kalah senjata. Bagaimanapun, itu harus ada di sana untuk dukungan file yang lebih baik, jadi itu harus ditangani. Akan menargetkan 1.0 pada ini.

Setelah memeriksa kasus penggunaan saya untuk ini sedikit lebih banyak, saya ingin menyarankannya untuk diimplementasikan sebagai sesuatu yang lebih fleksibel daripada sekadar tampilan tampilan/daftar. Yang benar-benar harus saya lakukan adalah mengambil flag querystring seperti ini:

&bentuk=[penuh|sederhana|tidak ada]

dan memiliki output yang mencerminkan tingkat detail yang dipilih pengguna. Saya mencari cara untuk meretas ini, tetapi karena bidang disertakan/dikecualikan ketika kelas ModelResource dibuat, saya tidak dapat menemukan cara apa pun untuk mengubah apa yang tersedia nanti dalam siklus respons. Selain itu, objek permintaan tidak tersedia pada langkah-langkah dalam proses di mana saya ingin membuat keputusan seperti itu.

+1

Saya akan menyebutkan pemikiran ini di sini terlebih dahulu karena tampaknya relevan dengan masalah ini, tetapi mungkin perlu dipisahkan menjadi miliknya sendiri.

Jika mekanisme untuk menunjukkan bidang yang berbeda dikembangkan, akan berguna jika dapat diintegrasikan dengan otentikasi juga. Mampu mengekspos lebih banyak/lebih sedikit bidang tergantung pada izin pengguna akan sangat kuat. Jika ini sudah memungkinkan, saya belum dapat menemukan penyebutan itu.

+1

+1

+1

+1

+1

+1

+1

Saya berharap dapat mengontrol bidang yang ditampilkan (menggunakan bidang atau pengecualian) pada metode per (POST, PUT, GET) selain daftar/detail.

Berikut solusinya, lihat contoh di bawah: Anda tidak mengecualikan apa pun dari model sumber daya model asli (UserResource dalam contoh) sehingga akan penuh dalam tampilan indeksnya. Anda harus masuk ke metode dehidrasi modelresource yang menyertakan sub model Anda (BlogPostResource menyertakan penulis di dalamnya) dan cukup hapus elemen bundel.

contoh:

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

Jadi ketika Anda ingin membuat daftar pengguna, Anda masih mendapatkan semua bidang tetapi ketika Anda membuat daftar posting blog, misalnya, Anda bisa mendapatkan nama depan dan nama belakang penulis.

Bagaimana menurutmu?

Contoh solusi yang sangat, sangat kotor: Tidak menampilkan bidang proyek di list_view, tetapi melakukannya di detail_view, tanpa harus mengakses sumber daya itu sendiri, mendapatkan url itu sendiri tanpa hardcoding seharusnya memungkinkan tetapi tidak punya waktu untuk memeriksanya :

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

Saya juga akan naik kereta, tetapi apa yang ditunjukkan @ashwoods sudah cukup untuk membuat saya bertahan. Saya telah memodifikasinya sedikit menjadi sedikit lebih dinamis.

    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

Jadi saya memikirkan ini lagi dan menemukan sesuatu yang hampir membuat saya melakukan apa yang menurut saya dicari oleh @bmihelac .

Menggunakan contoh yang disediakan @ashwoods , misalkan kami hanya ingin menampilkan bidang proyek jika itu adalah respons detail:

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, menggunakan perbaikan dari @dericcrago untuk saat ini.

+1

+1

Implementasi sebagian di #526, tidak yakin saya menjual semuanya & tidak memiliki tes/dokumen.

Baru saja melihat tiket ini... dan juga seperti pendekatan 'bentuk' yang disebutkan oleh onyxfish di atas...

Memikirkan solusi saya di #526 agak terbatas, kalau-kalau orang menginginkan 'bentuk' yang berbeda dalam kasus lain ...

untuk saran untuk menghapus bidang setelah dehidrasi ... seluruh alasan saya adalah untuk menghindari menghitung nilai sejak awal.

Namun, ide untuk kait detail_dehydrate untuk memungkinkan menambahkan lebih banyak detail secara kondisional, saya suka.

Sepertinya dua kemungkinan implementasi termasuk tes dan dokumen tersedia. Saya menulis satu di #569 dan #538 juga melakukan fungsi serupa (#538 memungkinkan sedikit lebih banyak fleksibilitas karena use_in mungkin dapat dipanggil). Implementasi saya menambahkan atribut meta untuk mengontrol fungsi ini (yang konsisten dengan atribut fields saat ini) sementara #538 menambahkan atribut ke bidang. Keduanya tampak valid, hanya keputusan desain ke mana harus pergi. Menambahkan ke meta tampaknya konsisten bagi saya dan lebih mudah digunakan mengingat beberapa bidang dapat dibuat secara otomatis dan memodifikasi parameter inisialisasinya mungkin tidak dapat dilakukan. Alternatif lain adalah menggabungkan kedua permintaan tarik dan mengizinkan parameter use_in diatur secara otomatis berdasarkan atribut meta , namun ini tampaknya menambah lebih banyak kerumitan pada API daripada yang diperlukan. Terima kasih kepada @issackelly karena telah menunjukkan permintaan tarik terkait kepada saya.

[bergabung karena saya adalah penyebab awal di balik #538, itu adalah pembersihan #526 saya]
Sangat masuk akal ... pendekatan Meta akan, memang, gel dengan daftar pengecualian untuk ModelResource, dll ...

Seperti yang saya katakan di tiket lain, solusi "sederhana" seperti ini, IMHO, cukup untuk rilis 1.0... .

@funkybob Setuju, tentu saja solusi yang lebih kompleks akan sangat membantu dari sisi klien, tetapi alangkah baiknya jika fungsi ini disertakan secepatnya sehingga dapat mulai digunakan sebelum 1.0 dirilis.

Sebenarnya menggunakan PR dalam aplikasi produksi, saya sangat menyukai fleksibilitas panggilan balik yang disediakan oleh #538. Saya memiliki beberapa kasus penggunaan di mana saya harus menyembunyikan sumber daya saat runtime berdasarkan izin.

Ini tidak mungkin bagi saya menggunakan #569

Hai, ada kabar? PR itu membuat hidup jadi lebih mudah, terima kasih!

Pergi dengan hack yang disediakan oleh @dericcrago

+1

Solusi sederhana yang saya gunakan adalah mengganti metode get_detail & get_list untuk mengedit bidang tersebut.
Ini menghemat overhead untuk benar-benar mengambil data untuk bidang dan kemudian menghapusnya dari bundel, tetapi saya tidak yakin apakah metode ini aman, karena sepertinya objek Resource tidak dibuat pada setiap panggilan api.
Akan sangat bagus jika seseorang dapat mengomentari ini.

Berikut kodenya:

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

solusi lain adalah memiliki sumber daya yang berbeda untuk tampilan detail dan daftar:

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 untuk solusi @dnozay

+1 @dnozay , luar biasa

Perhatikan bahwa jika Anda ingin get_resource_uri berfungsi dengan benar dengan tampilan detail pengguna, Anda harus menambahkan yang berikut ini setelah UserResource ditentukan.

UserResourceDetail.get_resource_uri = UserResource().get_resource_uri

Jika tidak, resource_uri akan kosong di semua respons detail.

Mungkin terkait: #1265

Apakah halaman ini membantu?
0 / 5 - 0 peringkat