İçeriğe geç

DRF Özel Viewset Aksiyonları #İpuçları3

Herkese merhabalar.

Geçenlerde Twitter üzerinden gelen bir viewseti nasıl genişletebilirim sorusunu cevapladıktan sonra, ufak bir ipucu olarak da yazayım belki birilerinin işine yarar diye bu yazıyı bir gece vakti kaleme alıyorum. Saat 03:24. Soru gayet açık bir viewseti nasıl genişletebiliriz?

Viewsetler özet.

Viewsetler Django Rest Frameworkün en güçlü yanlarından biri. Viewsetler ile uygulamanız genelinde Django modelleriniz ile etkileşime geçecek olan kısımlara çok hızlı bir şekilde şablonlar oluşturabilir, açıkça url tanımlamalarını pas geçerek kendinizi tekrarlamaktan kurtulabilirsiniz.

Viewsetler normal viewlar  aksine aksiyonlar ile çalışır. Örneğin create, retrieve, partial_update.

Örnek bir kullanım verecek olursak. Aşağıda ki kod bloğu sistemimiz genelinde bulunan kitaplar üzerinde basit CRUD işlemleri yapabilme yeteneğini bize sağlar.

from rest_framework import viewsets, parsers, authentication, permissions

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    parser_classes = [parsers.JSONParser]

 

Yazdığımız bu viewset gelen tüm istekleri bir aksiyonla karşılar işlemleri yürütür.

Ayrıca viewsetler ile çalışırken açıkça url tanımlamaları da yapmamıza da gerek yoktur. Viewseti bir routera kaydedip gerekli olan tüm yönlendirmeleri routera bırakabiliriz.

from .views import BookViewSet
from rest_framework import routers

router = routers.DefaultRouter()

router.register(r'books',BookViewSet)

urlpatterns = router.urls

 

Buraya kadar olan viewsets nedir hatırlatmasını hallettikten sonra asıl konumuza gelelim.


Viewset aksiyonları.

Viewsetlar aksiyonlar ile çalışır bunda hem fikiriz fakat bazen yerleşik olarak kullanılan aksiyonlar isteklerimizi tam olarak karşılamayabilir. Yeni ihtiyaçlar ortaya çıkabilir.

Örneğin uygulamamızın bazı kısımlarında, yerleşik olarak kullanılan HTTP content, media type dışına çıkmak veya bazı özel kullanıcılar için özel endpointler tasarlamak gibi.

Bu gibi durumlarda harici bir view yazmaktansa action dekaratörü ile kendi yazacağımız aksiyonları viewsetımıza bir view gibi çalışması için bağlayabiliriz. Yazacağımız aksiyon, tüm koleksiyon üzerinde işlem yapabileceği gibi spesifik bir nesne üzerinde de çalışabilir.

Örnek bir senaryo kurup üzerinden ilerleyelim. Aşağıdaki gibi 2 yeni isteğin geldiğini varsayalım.

  1. Kitaplarımızın artık kapak fotoğraflarını da tutmak istiyoruz.
  2. Sadece admin statüsünde bulunan kullanıcılarına özel bir endpoint sağlayarak tek istekle tüm kitapları silebilmesini istiyoruz.
from rest_framework.decorators import action #new

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    parser_classes = [parsers.JSONParser]

    @action(
        methods=["POST"],
        detail=True,
        serializer_class=BookCoverUploadSerializer,
        parser_classes=[parsers.MultiPartParser],
    )
    def upload_cover(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.serializer_class(instance, data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return response.Response(
                {"message": "cover image uploaded successfully."},
                status=status.HTTP_200_OK,
            )
        return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(
        methods=["DELETE"],
        detail=False,
        permission_classes=[
            permissions.IsAdminUser,
        ],
        authentication_classes=[authentication.BasicAuthentication],
    )
    def delete_all(self, request, *args, **kwargs):
        Book.objects.all().delete()
        return response.Response(
            {"message": "All books deleted successfully."}, status=status.HTTP_200_OK
        )

 

@action dekoratörünü bağlayarak aksiyonu yazmaya başlıyoruz. Ardından o aksiyonun kabul edeceği HTTP metodlarını belirtiyoruz. detail parametresi booelan değer alan ve o aksiyonun bir koleksiyon üzerinde mi yoksa nesne üzerinde mi çalışacağını belirttiğimiz kısım.

Dikkat ettiyseniz viewsette serializer_class, ve kabul edilecek content type’i belirlemiştik. Özelleştirilmiş bir aksiyon yazarken viewset seviyesinde tanımlanmış olan tüm ayarlamaları ezebiliriz. Viewset’in yerleşik aksiyonları viewset bloğunda tanımlanan ayarlar, özell aksiyonlar ise kendilerine tanımladığımız ayarlamalar ile birlikte çalışacaktır. Bir tanımlama yapılmaz ise viewset bloğundaki tanımlamalar kullanılacaktır. Basit iş yüküne sahip olduklarından dolayı aksiyon gövdelerini açıklamayı pas geçiyorum.

Bir aksiyon ekledikten sonra aynı viewsetlerda olduğu üzere gerekli url’leri açıkça belirtmiyoruz. Görevi yine routera bırakıyoruz.

Dekoratöre bir url_path parametresi geçmemis isek router yönlendirmeler için, default olarak metod ismini kullanır.

Örneğin:

https://example.com/api/books/delete_all/

https://example.com/api/books/1/upload_cover/


Özet.

Basit ve hızlı bir yazı oldu. Fakat kod tutarlılığının nasıl sağlanabileceği veya çalıştığımız toolun esnekliğini ve gücü hakkında size de bir fikir vermiş olmasını umuyorum. İmla hataları için saati de göze alarak affınıza sığınıyorum 🙂 Daha detaylı bilgi için dökümantasyon linki burada.

Django Rest Framework ile ilgili daha fazla yazıya göz atmak ister miydininz?

İyi günler!

 

 

Tarih:Uncategorized

İlk Yorumu Siz Yapın

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Göster
Gizle