Saya ingin menyediakan dua serialisator yang berbeda namun dapat memperoleh manfaat dari semua fasilitas ModelViewSet
:
- Saat melihat daftar objek, saya ingin setiap objek memiliki url yang mengarahkan ulang ke rinciannya dan setiap relasi lain muncul menggunakan
__unicode __
model target;
contoh:
{
"url": "http://127.0.0.1:8000/database/gruppi/2/",
"nome": "universitari",
"descrizione": "unitn!",
"creatore": "emilio",
"accesso": "CHI",
"membri": [
"emilio",
"michele",
"luisa",
"ivan",
"saverio"
]
}
- Saat melihat detail objek, saya ingin menggunakan default
HyperlinkedModelSerializer
contoh:
{
"url": "http://127.0.0.1:8000/database/gruppi/2/",
"nome": "universitari",
"descrizione": "unitn!",
"creatore": "http://127.0.0.1:8000/database/utenti/3/",
"accesso": "CHI",
"membri": [
"http://127.0.0.1:8000/database/utenti/3/",
"http://127.0.0.1:8000/database/utenti/4/",
"http://127.0.0.1:8000/database/utenti/5/",
"http://127.0.0.1:8000/database/utenti/6/",
"http://127.0.0.1:8000/database/utenti/7/"
]
}
Saya berhasil membuat semua ini berfungsi seperti yang saya inginkan dengan cara berikut:
serializers.py
# serializer to use when showing a list
class ListaGruppi(serializers.HyperlinkedModelSerializer):
membri = serializers.RelatedField(many = True)
creatore = serializers.RelatedField(many = False)
class Meta:
model = models.Gruppi
# serializer to use when showing the details
class DettaglioGruppi(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Gruppi
views.py
class DualSerializerViewSet(viewsets.ModelViewSet):
"""
ViewSet providing different serializers for list and detail views.
Use list_serializer and detail_serializer to provide them
"""
def list(self, *args, **kwargs):
self.serializer_class = self.list_serializer
return viewsets.ModelViewSet.list(self, *args, **kwargs)
def retrieve(self, *args, **kwargs):
self.serializer_class = self.detail_serializer
return viewsets.ModelViewSet.retrieve(self, *args, **kwargs)
class GruppiViewSet(DualSerializerViewSet):
model = models.Gruppi
list_serializer = serializers.ListaGruppi
detail_serializer = serializers.DettaglioGruppi
# etc.
Pada dasarnya saya mendeteksi ketika pengguna meminta tampilan daftar atau tampilan rinci dan berubah serializer_class
sesuai dengan kebutuhan saya. Saya tidak benar-benar puas dengan kode ini, sepertinya hack kotor dan, yang paling penting, bagaimana jika dua pengguna meminta daftar dan detail pada saat yang sama?
Apakah ada cara yang lebih baik untuk mencapai ini menggunakan ModelViewSets
atau saya harus kembali menggunakan GenericAPIView
?
EDIT:
Berikut cara melakukannya menggunakan basis kustom ModelViewSet
:
class MultiSerializerViewSet(viewsets.ModelViewSet):
serializers = {
'default': None,
}
def get_serializer_class(self):
return self.serializers.get(self.action,
self.serializers['default'])
class GruppiViewSet(MultiSerializerViewSet):
model = models.Gruppi
serializers = {
'list': serializers.ListaGruppi,
'detail': serializers.DettaglioGruppi,
# etc.
}
sumber
Jawaban:
Ganti
get_serializer_class
metode Anda . Metode ini digunakan dalam mixins model Anda untuk mengambil kelas Serializer yang tepat.Perhatikan bahwa ada juga
get_serializer
metode yang mengembalikan instance Serializer yang benarsumber
if hasattr(self, 'action') and self.action == 'list'
pk
objek yang diminta, jika tindakan ituretrieve
?Anda mungkin menemukan mixin ini berguna, itu menimpa metode get_serializer_class dan memungkinkan Anda untuk mendeklarasikan dict yang memetakan class action dan serializer atau mundur ke perilaku biasa.
sumber
Jawaban ini sama dengan jawaban yang diterima tetapi saya lebih suka melakukannya dengan cara ini.
Pandangan umum
sumber
Mengenai menyediakan berbagai serialisator, mengapa tidak ada orang yang menggunakan pendekatan yang memeriksa metode HTTP? Ini IMO lebih jelas dan tidak memerlukan pemeriksaan tambahan.
Kredit / sumber: https://github.com/encode/django-rest-framework/issues/1563#issuecomment-42357718
sumber
list
danretrieve
tindakan yang berbeda, Anda memiliki masalah yang sama-sama menggunakanGET
metode. Inilah sebabnya mengapa kerangka istirahat Django ViewSets menggunakan konsep tindakan , yang serupa, tetapi sedikit berbeda dari metode http yang sesuai.Berdasarkan @gonz dan @ user2734679 jawaban saya telah membuat paket python kecil ini yang memberikan fungsionalitas ini dalam bentuk kelas anak ModelViewset. Inilah cara kerjanya.
sumber
Meskipun mendefinisikan beberapa Serializer dengan cara atau cara lain tampaknya merupakan cara yang paling jelas didokumentasikan , FWIW ada pendekatan alternatif yang mengacu pada kode terdokumentasi lain dan yang memungkinkan lewat argumen ke serializer saat instantiated. Saya pikir itu mungkin akan cenderung lebih bermanfaat jika Anda perlu menghasilkan logika berdasarkan berbagai faktor, seperti tingkat admin pengguna, tindakan yang dipanggil, bahkan mungkin atribut dari instance.
Bagian pertama dari teka-teki adalah dokumentasi tentang memodifikasi serializer secara dinamis pada titik instantiasi . Dokumentasi itu tidak menjelaskan cara memanggil kode ini dari viewset atau bagaimana mengubah status bidang yang hanya dibaca setelah initated - tetapi itu tidak terlalu sulit.
Bagian kedua - metode get_serializer juga didokumentasikan - (hanya sedikit lebih jauh di bawah halaman dari get_serializer_class di bawah 'metode lain') sehingga harus aman untuk diandalkan (dan sumbernya sangat sederhana, yang semoga berarti lebih sedikit kesempatan untuk tidak sengaja) efek samping yang dihasilkan dari modifikasi). Periksa sumbernya di bawah GenericAPIView (ModelViewSet - dan semua kelas tampilan bawaan lainnya) - mewarisi dari GenericAPIView yang mendefinisikan get_serializer.
Menyatukan keduanya Anda bisa melakukan sesuatu seperti ini:
Dalam file serializers (untuk saya base_serializers.py):
Kemudian di viewset Anda, Anda mungkin melakukan sesuatu seperti ini:
Dan itu seharusnya! Menggunakan MyViewSet sekarang harus instantiate MyDynamicSerializer Anda dengan argumen yang Anda inginkan - dan dengan asumsi serializer Anda mewarisi dari DynamicFieldsModelSerializer Anda, ia harus tahu apa yang harus dilakukan.
Mungkin perlu disebutkan bahwa dapat masuk akal jika Anda ingin mengadaptasi serializer dengan beberapa cara lain ... misalnya untuk melakukan hal-hal seperti mengambil dalam daftar read_only_exceptions dan menggunakannya untuk daftar putih daripada bidang daftar hitam (yang cenderung saya lakukan). Saya juga merasa berguna untuk mengatur bidang ke tuple kosong jika tidak lulus dan kemudian hanya menghapus centang untuk Tidak Ada ... dan saya menetapkan definisi bidang saya pada Serializers bawaan saya ke ' semua '. Ini berarti tidak ada bidang yang tidak dilewati ketika membuat serializer selamat secara tidak sengaja dan saya juga tidak perlu membandingkan permintaan serializer dengan definisi kelas serializer bawaan untuk mengetahui apa yang disertakan ... misalnya dalam init dari DynamicFieldsModelSerializer:
NB Jika saya hanya ingin dua atau tiga kelas yang dipetakan ke tindakan yang berbeda dan / atau saya tidak ingin perilaku serializer yang dinamis, saya mungkin akan menggunakan salah satu pendekatan yang disebutkan oleh orang lain di sini, tapi saya pikir ini layak disajikan sebagai alternatif , khususnya mengingat kegunaannya yang lain.
sumber