Django Rest Framework -5
Serializer İle İç İçe Yorum
İlk başta makalelerimizin yorumları olması için bir yorum modeline ihtiyacımız var. Hadi gelin bunu oluşturalım.Ben bunun için yeni bir APP oluşturacağım.
python manage.py startapp COMMENTAPP
Yorum uygulamamızı hemen settings.py dosyası üzerinden INSTALLED_APPS listesine de ekledikten sonra COMMENTAPP klasörüne bir api klasörü oluşturalım. Klasörün bir python modulü olarak gözükmesi için içerisine __init__.py adında python dosyası oluşturalım.
Şimdi ise api klasörümüzün içerisine sayfalama işlemleri için paginations.py dosyasını , izinler için permissions.py dosyasını , serializerlarimiz için serializers.py dosyasını gerekli url’lerimizi oluşturmak için urls.py dosyasını ve son olarak da gerekli view’lerimizi yazmak için de views.py dosyasını oluşturuyoruz.
Şimdi ise yorum modelimizi oluşturalım. Oluşturmuş olduğumuz COMMENTAPP klasörünün içerisindeki models.py dosyasına gelip modelimizi oluşturalım.
class CommentModel(models.Model):
Author = models.ForeignKey(User,on_delete=models.CASCADE)
CreatedDate = models.DateTimeField(auto_now_add=True,verbose_name="Yorum Tarihi")
ModifiedDate = models.DateTimeField(auto_now=True,editable=False)
CommentText = models.CharField(max_length=150,verbose_name="Yorum İçeriği")
Post = models.ForeignKey(PostModel,on_delete=models.CASCADE,related_name="comments")
Parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
null=True,blank=True,
related_name="replies")
class Meta:
db_table="Comments"
verbose_name = "Yorum"
verbose_name_plural="Yorumlar"
ordering=("CreatedDate",)
Modelimizi oluşturduk. Oluşturduğumuz alanlara göz atalım.
1- Author : Yorumu yazan kullanıcıdır. Foreign key olarak User modelini verdik.
2 - CreatedDate : Yorumun oluşturulma tarihidir. auto_now_add ile yorum oluştuğu anda sadece o ana özel saati tarihi alır ve kayıt eder. Yorum güncellense dahi bu field güncellenmez.
3 - ModifiedDate : Yorumun güncellenme tarihidir. Eğer yorum güncellenirse,bu field alanımızın tarih ve saati de güncellenir.
4 - CommentText : Yorumun içeriğidir.
5 - Post : Yorumun atılacağı makaledir. Foreign key olarak oluşturmuş olduğumuz PostModel’i vereceğiz.
6 - Parent : İç içe yorum atabileceğimizden dolayı parent’ı yani bu yorumun bir parent’ı var mı yok mu onu tutacak bu field. Bu yüzden Foreign Key olarak “self” ile kendisini niteleyecektir. Ancak null ve blank özellikleri True olmalıdır. Çünkü her yorum bir yorumun yorumu olmayabilir.
Class Meta özel sınıfı ile de gerekli veritabanındaki tablo ismi ve admin panelinde gözükecek olan isimleri özelleştirdik. Ek olarak ordering vererek oluşturma tarihini verdim yorumlarımızın sıralanması için.
Şimdi bu sınıfa birkaç method daha yazacağız ve bunlar önemli methodlar olacaktır.
class CommentModel(models.Model):
Author = models.ForeignKey(User,on_delete=models.CASCADE)
CreatedDate = models.DateTimeField(auto_now_add=True,verbose_name="Yorum Tarihi")
ModifiedDate = models.DateTimeField(auto_now=True,editable=False)
CommentText = models.CharField(max_length=150,verbose_name="Yorum İçeriği")
Post = models.ForeignKey(PostModel,on_delete=models.CASCADE,related_name="comments")
Parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
null=True,blank=True,
related_name="replies")
class Meta:
db_table="Comments"
verbose_name = "Yorum"
verbose_name_plural="Yorumlar"
ordering=("CreatedDate",)
def children(self):
return CommentModel.objects.filter(Parent=self)
@property
def any_children(self):
return CommentModel.objects.filter(Parent=self).exists()
İlk oluşturduğumuz method children methodudur. Bu methodun işlevini açıklayalım. Basitçe parent’ı kendisi olan diğer yorumları geri döndürür. Bunu da bir yorumun alt yorumlarını bulmak için birazdan kullanacağız.
Diğer oluşturduğumuz ise bir property’dir. Bir yorumun children’ı var mı yani alt yorumları var mı yok mu onu bizlere döndürecek olan propertydir.
Oluşturduğumuz dosyalara göz atalım.
Evet dosyalarımız bu şekilde olmalıdır. Şimdi ana urls.py dosyasında gerekli include ayarlarını yapalım. Bunu göstermeyeceğim çünkü django konusu. Oluşturmuş olduğumuz api klasörünün içerisindeki urls.py dosyasına gelelim.
urlpatterns = [
path("list/",CommentListAPIView.as_view(),name="listComments"),
]
list adında bir path oluşturdum. Bu path’e de birazdan oluşturacak olduğumuz CommentListAPIView adında bir view verdim. Şimdi api klasörünün içerisideki views.py dosyasında bu ismini verdiğimiz view’imizi oluşturalım.
class CommentListAPIView(ListAPIView):
serializer_class = CommentListSerializers
pagination_class = CommentPagination
def get_queryset(self):
queryset=CommentModel.objects.filter(Parent=None)
return queryset
Burada yaptıklarımızı anlatalım. get_queryset ile Parent’ı olmayan yorumları çekeceğiz. Peki parent’ı oan yorumları nasıl çekeceğiz diyecek olursanız bunu birazdan bir makalenin detay sayfasına gittiğimizde çekeceğiz.
serializer_class ile de birazdan oluşturacak olduğumuz CommentListSerializers’i oluşturuyorum. Hemen serializers.py dosyamıza gelip serializer’ımızı oluşturalım.
class CommentListSerializers(ModelSerializer):
Replies = serializers.SerializerMethodField()
Author = serializers.SerializerMethodField()
def get_Replies(self,obj):
if obj.any_children:
return CommentListSerializers(obj.children(),many=True).data
def get_Author(self,obj):
return obj.Author.username
class Meta:
model=CommentModel
fields=("Author","CreatedDate","ModifiedDate",
"TotalLikes","Post","Parent","CommentText","Replies")
Burada Author diye bir alan oluşturup SerializerMethodField yaptım. get_Author ile de bu methodu yazdım. Bu method sadecce yorumu yazan kullanıcının ID numarasını değil de kullanıcı adını döndürecek.
Diğer bir oluşturduğum SerializerMethodField ise Replies alanıdır. Replies ile yorumumuzun içindeki diğer child yorumları getireceğiz.Peki bu method ne yapıyor gelin anlatalım.
def get_Replies(self,obj):
if obj.any_children:
return CommentListSerializers(obj.children(),many=True).data
Az önce modelimizde oluşturmuş olduğumuz property’i hatırlayalım. if obj.any_children propertysi ile o yorumumuzun child’ları var mı yok mu onu kontrol ediyoruz. Eğer altında yorumları varsa olduğumuz Serializer’i iç içe kullanarak obj.children methodundan(Modelimizde oluşturduğumuz method) gelen Alt yorumların queryset’ini veriyoruz. many=True diyerek de serializer’imize “Sana birdan fazla veri göndereceğim” diyoruz.
Şimdi URL adresimize giderek olanlara bakalım. Tabi birkaç yorum ekleyelim önce.
Gördüğünüz gibi yorumlarımız iç içe gelmektedir.İşlemimiz başarıyla gerçekleşti. Şimdi hızlıca makalemizin detay sayfasında da bu yorumları gönderelim.
Oluşturmuş olduğumuz POSTAPP’imizde api klasörünün içerisindeki serializers.py dosyasını açalım.
class PostDetailSerializer(serializers.ModelSerializer):
Author = serializers.SerializerMethodField()
Yorumlar = serializers.SerializerMethodField(
method_name="get_Yorumlar")
def get_Yorumlar(self,obj):
yorumlar = obj.comments.filter(Parent=None)
serializer = CommentListSerializers(yorumlar,many=True)
if serializer.data==[]:
return None
return serializer.data
def get_Author(self,obj):
return obj.Author.username
class Meta:
model = PostModel
fields=[
"Author",
"Title","Content",'CreatedDate','ModifiedDate','Image',
'Yorumlar'
]
Yorumlar ile bir SerializerMethodField oluşturdum ve bu methodu inceleyelim biraz.
def get_Yorumlar(self, obj):
yorumlar = obj.comments.filter(Parent=None)
serializer = CommentListSerializers(yorumlar, many=True)
if serializer.data == []:
return None
return serializer.data
İçerisine yorumlar adında değişken oluşturarak içerisine obj ile Parent’ı None olan yorumları çekiyorum ve serializer oluşturup bunu az önce oluşturmuş olduğumuz serializer’i veriyorum. Bu serializer’imize ise yorumlar değişkenini (queryseti) veriyorum. Ardından many=True diyerek serializerimize birden fazla veri göndereceğimizi belirtiyorum. Eğer serializerimizden boş liste geliyorsa None olarak return ettiriyorum. Ancak gelen bir veri varsa serializer.data’yı döndürüyorum.
Makalemizin detay sayfasına gidelim
Gördüğünüz gibi makalemizin detay sayfasında iç içe yorumları listeleyebiliyoruz.
Comments
There are no comments yet.