বাংলায় জ্যাঙ্গো

কখনো কখনো Foreign Key ফিল্ডে আমাদের ডায়নামিক ভাবে মডেল যুক্ত করার দরকার হয়। যদিও সাধারণ ভাবে একটিForeignKey ফিল্ডে একাধিক মডেল রাখা সম্ভব না (যেখান থেকে আমরা ইচ্ছামত যেকোন একটা মডেল সিলেক্ট করতে পারি)! এক্ষেত্রে আমরা দুইভাবে কাজ করতে পারি, একাধিক Nullable ফরেন কী ফিল্ড তৈরি করে অথবা জেনেরিক রিলেশন ব্যবহার করে।

প্রথমে দেখব একাধিক ফরেন কী ফিল্ড ব্যবহার করে অপারেশনগুলো কিভাবে করা যায়। ধরা যাক আমাদের কাছে Post , Comment এবং Review নামে তিনটি মডেল আছেঃ

# পোস্ট মডেল
class Post(models.Model):
    text = models.TextField()

# কমেন্ট মডেল
class Comment(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')

# রিভিউ মডেল
class Review(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviews')
    comment = models.ForeignKey(Comment, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviews')

 

তো আমরা নিচের মত অপারেশন চালাতে পারিঃ

# 1.1 একটি পোস্ট তৈরি করি
post_object = Post.objects.create(text='new post')

# 1.2 পোস্ট এর জন্য একটি রিভিউ তৈরি করি। ( রিভিউ মডেল থেকে! ) 
review_object_for_post = Review.objects.create(text='review for awesome post', post=post_object)

# 1.3 পোস্ট এর জন্য আরেকটি রিভিউ তৈরি করি। (পোস্ট অবজেক্ট থেকে!) 
review_object_for_post_reverse = post_object.reviews.create(text='another review for awesome post' )

# 1.4 নির্দিষ্ট একটি পোস্টের সকল রিভিউ ফিল্টার করি। (রিভিউ মডেল থেকে) 
all_reviews_for_specific_post = Review.objects.filter(post=post_object)

# 1.5 নির্দিষ্ট একটি পোস্টের সকল রিভিউ ফিল্টার করি। (পোস্ট অবজেক্ট থেকে) 
all_reviews_for_specific_post_reverse = post_object.reviews.all()

# 1.6 নির্দিষ্ট একটা রিভিউ অবজেক্ট থেকে সেটার পোস্ট অব্জেক্ট বের করি
post_object_of_specific_review = review_object_for_post.post

 

একই স্টাইলে আমরা কমেন্টের অপারেশন গুলোও করতে পারি।

# 2.1 একটি কমেন্ট তৈরি করি 
comment_object = Comment.objects.create(text='new comment', post=post_object)

# 2.2 কমেন্ট এর জন্য একটি রিভিউ তৈরি করি। ( রিভিউ মডেল থেকে! ) 
review_object_for_comment = Review.objects.create(text='review for awesome Comment', comment=comment_object)

# 2.3 কমেন্ট এর জন্য একটি রিভিউ তৈরি করি। (কমেন্ট অবজেক্ট থেকে!) 
review_object_for_comment_reverse = comment_object.reviews.create(text='another review for awesome Comment' )

# 2.4 নির্দিষ্ট একটি কমেন্টের সকল রিভিউ ফিল্টার করি (রিভিউ মডেল থেকে) 
all_reviews_for_specific_comment = Review.objects.filter(comment=comment_object)

# 2.5 নির্দিষ্ট একটি কমেন্টের সকল রিভিউ ফিল্টার করি (কমেন্ট অবজেক্ট থেকে) 
all_reviews_for_specific_comment_reverse = comment_object.reviews.all()

# 2.6 নির্দিষ্ট একটা রিভিউ অবজেক্ট থেকে সেটার কমেন্ট অব্জেক্ট বের করি
comment_object_of_specific_review = review_object_for_comment.comment

# আরো অনেক ধরনের কুয়েরি করতে পারি, সেগুলো না হয় আরেকদিন দেখব!

 

উপরের 1.6 এবং 2.6 নং কুয়েরিতে একটি সমস্যা আছে, একটা রিভিউ যেহেতু পোস্টেরও হতে পারে আবার কমেন্টেরও হতে পারে তাই আগে থেকে জানা না থাকলে এটা বের করা ঝামেলা যে কোনো একটা রিভিউ আসলে কার! Post এর নাকি Comment এর!?
সেক্ষেত্রে আমাদেরকে আগে চেক করে বের করতে হবে রিভিউটি কার, তারপর অবজেক্টটি গেট করতে পারব!
অনেকটা এভাবেঃ

if another_review.post:
    review_for = another_review.post

elif another_review.comment:
    review_for = another_review.comment

else:
    review_for = None

# যদি আরো কোন ফরেন কী ফিল্ড থাকে তাহলে সেগুলোও এভাবে চেক করতে হবে।

 

এই সমস্যা সহজে হ্যান্ডেল করতে পারি রিভিউতে একটি আলাদা ক্যারেক্টার ফিল্ড রেখে! যেখানে আমরা মডেলের নাম লিখে রাখব অর্থাৎ Post অথবা Comment ! পরে সেই ফিল্ড চেক করে দ্রুত বের করতে পারব এটা কার রিভিউ!

যাই হোক, ফরেন কী হিসেবে ডায়নামিক ভাবে (মাল্টিপল মডেল থেকে যেকোনো) মডেল সিলেক্ট করে দেয়ার জন্য ডিফল্ট ভাবে জ্যাঙ্গোতে সুন্দর একটা সিস্টেম আছে! ‘জেনেরিক রিলেশনস ‘ (Generic Relations )! এটা ব্যবহার করার জন্য আমাদেরকে নির্ভর করতে হবে জ্যাঙ্গোর বিল্টিন এপ ‘কন্টেন্ট টাইপ্স’ (ContentTypes) এর উপর! সংক্ষেপে, ContentTypes এপটি একটি জ্যঙ্গো প্রোজেক্টের সকল মডেলের আইডিগুলো সেভ করে রাখে! আপাতত এতটুকু জানাই আমাদের জন্য যথেষ্ট 😛 ! এখন দেখব উপরের কাজটা কনটেন্ট টাইপ আর জেনেরিক রিলেশন দিয়ে কিভাবে করে ফেলা যায়!

প্রথমেই আমদের তিনটা মডেল তৈরি করে নেই!

# এই তিনটি ক্লাস ইম্পোর্ট করতে হবে 
from django.contrib.contenttypes.fields import GenericForeignKey 
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType


# রিভিউ মডেল, জেনেরিক রিলেশনের সাথে! 
class Review(models.Model):
    text = models.TextField()

    # নিচের তিনটি ফিল্ড আবশ্যক, এভাবেই লেখা যাবে
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()

# পোস্ট মডেল, রিভার্স কুয়েরি করার জন্য রিভিউ এর সাথে জেনেরিক রিলেশন করা। 
class Post(models.Model):
    text = models.TextField() 
    reviews = GenericRelation(Review, related_query_name='posts')


# কমেন্ট মডেল, রিভার্স কুয়েরি করার জন্য রিভিউ এর সাথে জেনেরিক রিলেশন করা। 
class Comment(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    reviews = GenericRelation(Review, related_query_name=' comments')

 

এক্ষেত্রে সুবিধা হল, এর পর আরও নতুন যত মডেলের সাথেই আমি রিভিউ এর রিলেশন করতে চাইনা কেন আমাকে রিভিউ মডেলে চেঞ্জ করতে হবেনা, জাস্ট নতুন মডেলের মধ্যে reviews = GenericRelation(Review) দিয়ে দিলেই কাজ শেষ!

# 3.1 পোস্ট এবং কমেন্ট অবজেক্ট তৈরি করি 
post_object = Post.objects.create(text='new post')
comment_object = Comment.objects.create(text='new comment ', post=post_object)

# 3.2 রিভিউ মডেল থেকে নির্দিষ্ট পোস্ট এবং কমেন্টের জন্য রিভিউ তৈরি করি
review_object_for_post = Review.objects.create(text='awesome post', content_object=post_object)
review_object_for_comment = Review.objects.create(text='awesome comment', content_object=comment_object)

# নির্দিষ্ট পোস্ট অবজেক্ট এবং কমেন্ট অবজেক্ট থেকে সেগুলোর রিভিউ তৈরি করি
review_object_for_post_reverse = post_object.reviews.create(text='awesome post')
review_object_for_comment_reverse = post_object.reviews.create(text='awesome comment')

# 3.3 রিভিউ মডেল থেকে নির্দিষ্ট পোস্ট অবজেক্ট এবং কমেন্ট অবজেক্ট এর সকল রিভিউ ফিল্টার করি
all_reviews_for_specific_post = Review.objects.filter(posts=post_object)
all_reviews_for_specific_comment = Review.objects.filter(comments=comment_object)

# 3.4 নির্দিষ্ট পোস্ট অবজেক্ট এবং কমেন্ট অবজেক্ট থেকে সেগুলোর সকল রিভিউ ফিল্টার করি
all_reviews_for_specific_post_reverse = post_object.reviews.all()
all_reviews_for_specific_comment_reverse = comment_object.reviews.all()

# 3.5 নির্দিষ্ট রিভিউ অবজেক্ট থেকে সেটার পোস্ট 'বা' কমেন্ট অবজেক্ট বের করি
post_or_comment_object_for_specific_review = review_object_for_post.content_type
post_or_comment_object_for_specific_review = review_object_for_comment.content_type

 

—————————————-
লেখাটি নিজের জন্যই নোট হিসেবে রাখলাম, পরে আরো আপডেট করার ইচ্ছা আছে ইনশাল্লাহ …

Leave a Reply

avatar
  Subscribe  
Notify of