জ্যাঙ্গোর ওআরএম ব্যবহার করে এলোমেলো রেকর্ড কীভাবে টানবেন?


176

আমার কাছে এমন একটি মডেল রয়েছে যা আমি আমার সাইটে উপস্থাপিত চিত্রগুলির প্রতিনিধিত্ব করি। মূল ওয়েবপৃষ্ঠায় আমি তাদের কয়েকটি প্রদর্শন করতে চাই: সর্বাধিক জনপ্রিয়, এমন একটি যা বেশিরভাগ সময় দেখা হয় নি, সর্বাধিক জনপ্রিয় এবং একটি এলোমেলো।

আমি জ্যাঙ্গো 1.0.2 ব্যবহার করছি।

তাদের মধ্যে প্রথম 3 জন জ্যাঙ্গো মডেল ব্যবহার করে টানতে সহজ, শেষটি (এলোমেলো) আমাকে কিছুটা সমস্যা দেয় causes আমি আমার দৃষ্টিতে এটির মতো কিছুতে কোড করতে পারি:

number_of_records = models.Painting.objects.count()
random_index = int(random.random()*number_of_records)+1
random_paint = models.Painting.get(pk = random_index)

এটি আমার দৃষ্টিতে দেখতে চাই এমন কোনও কিছুর মতো দেখাচ্ছে না - এটি সম্পূর্ণভাবে ডাটাবেস বিমূর্তির অংশ এবং মডেলটিতে থাকা উচিত। এছাড়াও, এখানে আমাকে মুছে ফেলা রেকর্ডগুলির যত্ন নিতে হবে (তারপরে সমস্ত রেকর্ডের সংখ্যা আমাকে সমস্ত সম্ভাব্য মূল মানগুলি আবরণ করবে না) এবং সম্ভবত প্রচুর অন্যান্য জিনিস।

অন্য কোনও বিকল্পগুলি কীভাবে আমি এটি করতে পারি, কোনওভাবে মডেল বিমূর্তনের অভ্যন্তরে?


আমার মতে, আপনি কীভাবে জিনিসগুলি প্রদর্শন করেন এবং কোন জিনিসগুলি প্রদর্শন করেন তা "ভিউ" স্তর বা ব্যবসায়িক যুক্তির অংশ যা এমভিসির "কন্ট্রোলার" স্তরে যেতে হবে।
গ্যাব্রিয়েল ডি'আন্টোনা

জাজানোতে নিয়ামকটি দর্শন view docs.djangoproject.com/en/dev/faq/general/…

উত্তর:


169

ব্যবহারের order_by('?')ফলে প্রোডাক্টের দ্বিতীয় দিন ডিবি সার্ভারটি মেরে ফেলা হবে। একটি ভাল উপায় একটি সম্পর্কিত একটি ডাটাবেস থেকে এলোমেলো সারি প্রাপ্ত মধ্যে বর্ণিত মত কিছু ।

from django.db.models.aggregates import Count
from random import randint

class PaintingManager(models.Manager):
    def random(self):
        count = self.aggregate(count=Count('id'))['count']
        random_index = randint(0, count - 1)
        return self.all()[random_index]

45
model.objects.aggregate(count=Count('id'))['count']ওভারের কী কী সুবিধা রয়েছেmodel.objects.all().count()
রায়ান স্যাক্সি

11
গৃহীত উত্তরের চেয়ে অনেক বেশি ভাল, নোট করুন যে এই পদ্ধতির দুটি এসকিউএল কোয়েরি করে। যদি গণনাটির মধ্যে পরিবর্তন হয় তবে সীমাবদ্ধতার ত্রুটি থেকে বেরিয়ে আসা সম্ভব হতে পারে।
নেলো মিত্রানীম

2
এটি একটি ভুল সমাধান। আপনার আইডিগুলি 0 থেকে শুরু না হলে এটি কাজ করবে না এবং আইডির সংকোচী না থাকলেও। বলুন, প্রথম রেকর্ডটি 500 থেকে শুরু হয় এবং শেষটি 599 হয় (স্বীকৃতি স্বরূপ)। তারপরে গণনাটি 54950 হবে Surely আমি জানি না কেন এত লোক কেন এটিকে উচ্চারণ করেছিল এবং এটি গ্রহণযোগ্য উত্তর হিসাবে চিহ্নিত হয়েছিল was
সাজিদ

1
@ সাজিদ: আপনি আমাকে কেন জিজ্ঞাসা করছেন? এই প্রশ্নটিতে আমার অবদানের সমষ্টি দেখতে বেশ সহজ: কোনও সংরক্ষণাগারটি পচা হওয়ার পরে একটি লিঙ্ক সম্পাদনা করা। এমনকি আমি উত্তরের কোনওটিতেও ভোট দিইনি। তবে আমি এটি মজাদার বলে মনে করি যে এই উত্তর এবং আপনি দাবী করেছেন .all()[randint(0, count - 1)]এটি কার্যকরভাবে উভয়ই কার্যকর। আমাদের জন্য "অফ-বাই-ওয়ান-ত্রুটি" নতুন করে সংজ্ঞায়িত করা এবং বোকা ভোটারদের দিকে চিত্কার করার পরিবর্তে উত্তরের কোন অংশটি ভুল বা দুর্বল তা চিহ্নিত করার দিকে আপনার মনোনিবেশ করা উচিত। (সম্ভবত এটি এটি ব্যবহার করছে না .objects?)
নাথন টগি

3
@NathanTuggy। ঠিক আছে আমার খারাপ। দুঃখিত
সজিদ

260

সহজভাবে ব্যবহার করুন:

MyModel.objects.order_by('?').first()

এটি ক্যোরিসেট এপিআইতে নথিভুক্ত করা হয়েছে ।


71
নথিভুক্ত হিসাবে এই পদ্ধতির খুব ধীর হতে পারে দয়া করে নোট করুন :)
নিকোলাস ডুমাজেট

6
"আপনি ব্যবহার করছেন ডাটাবেস ব্যাকএন্ডের উপর নির্ভর করে ব্যয়বহুল এবং ধীর হতে পারে" " - ডিফ্রেন্ট ডিবি ব্যাকেন্ডের কোনও অভিজ্ঞতা? (SQLite / MySQL / postgres)?
কেন্ডার

4
আমি এটি পরীক্ষা করিনি, সুতরাং এটি খাঁটি জল্পনা: সমস্ত আইটেম উদ্ধার করা এবং পাইথনে এলোমেলোভাবে সম্পাদন করার চেয়ে ধীর হওয়া উচিত কেন?
মুহুক

8
আমি পড়েছি যে এটি মাইএসকিএলে ধীরে ধীরে, কারণ মাইএসকিএলটিতে অবিশ্বাস্যভাবে অক্ষম র্যান্ডম ক্রম রয়েছে।
ব্র্যান্ডন হেনরি

33
শুধু কেন নয় random.choice(Model.objects.all())?
জামে

25

অর্ডার_বি ('?') সহ সমাধানগুলি:: আপনি যদি মাইএসকিউএল ব্যবহার করেন (অন্য ডেটাবেসগুলি জানেন না) তবে মাঝারি আকারের টেবিলগুলির জন্যও অত্যন্ত ধীর।

order_by('?')[:N]SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT Nক্যোয়ারিতে অনুবাদ করা হবে ।

এর অর্থ হ'ল টেবিলের প্রতিটি সারির জন্য RAND () ফাংশনটি কার্যকর করা হবে, তারপরে পুরো টেবিলটি এই ফাংশনের মান অনুসারে বাছাই করা হবে এবং তারপরে প্রথম এন রেকর্ডস ফিরিয়ে দেওয়া হবে। যদি আপনার টেবিলগুলি ছোট হয় তবে এটি ঠিক আছে। তবে বেশিরভাগ ক্ষেত্রে এটি খুব ধীর অনুসন্ধান query

আমি সাধারণ ফাংশন লিখেছিলাম যা আইডির গর্ত থাকলেও (কিছু সারি মুছে ফেলা হয়েছে) কাজ করে:

def get_random_item(model, max_id=None):
    if max_id is None:
        max_id = model.objects.aggregate(Max('id')).values()[0]
    min_id = math.ceil(max_id*random.random())
    return model.objects.filter(id__gte=min_id)[0]

এটি প্রায় সব ক্ষেত্রেই অর্ডার_ ((??)) এর চেয়ে দ্রুত।


30
এছাড়াও, দুঃখের বিষয়, এলোমেলো থেকে অনেক দূরে। আপনার যদি আইডি 1 এবং অন্য 100 আইডি সহ রেকর্ড থাকে, তবে এটি দ্বিতীয় 99% সময়ের সাথে ফিরে আসবে।
ডিএস


10

এই ধরণের জিনিসটি করতে আপনি আপনার মডেলটিতে একটি পরিচালক তৈরি করতে পারেন । প্রথম বোঝার জন্য কি একজন পরিচালক, Painting.objectsপদ্ধতি একজন পরিচালক যে রয়েছে all(), filter(), get(), ইত্যাদি আপনার নিজের ম্যানেজার তৈরি করা আপনাকে প্রাক ফিল্টার ফলাফল এবং এই সব একই পদ্ধতি, সেইসাথে আপনার নিজস্ব পদ্ধতি, ফলাফলে কাজ আছে পারবেন ।

সম্পাদনা : order_by['?']পদ্ধতিটি প্রতিবিম্বিত করতে আমি আমার কোডটি পরিবর্তন করেছি । নোট করুন যে পরিচালকটি সীমাহীন সংখ্যক এলোমেলো মডেল দেয়। এর কারণে আমি কীভাবে একটি একক মডেল পেতে পারি তা দেখানোর জন্য আমি কিছুটা কোড কোড অন্তর্ভুক্ত করেছি।

from django.db import models

class RandomManager(models.Manager):
    def get_query_set(self):
        return super(RandomManager, self).get_query_set().order_by('?')

class Painting(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    randoms = RandomManager() # The random-specific manager.

ব্যবহার

random_painting = Painting.randoms.all()[0]

শেষ অবধি, আপনার মডেলগুলিতে অনেক পরিচালক থাকতে পারেন, তাই নির্দ্বিধায় একটি LeastViewsManager()বা তৈরি করতে MostPopularManager()


3
Get () ব্যবহার করা কেবলমাত্র তখনই চলতে পারে যদি আপনার pks ক্রমাগত থাকে, অর্থাৎ আপনি কোনও আইটেম কখনও মুছবেন না। অন্যথায় আপনি সম্ভবত চেষ্টা করে এমন একটি পিকে পাবেন যা বিদ্যমান নেই। .All () [এলোমেলো_আইডেক্স] ব্যবহার করা এই সমস্যায় ভুগছে না এবং কোনও কম দক্ষও নয়।
ড্যানিয়েল রোজম্যান

আমি বুঝতে পেরেছিলাম যে কারণেই আমার উদাহরণটি কোনও ব্যবস্থাপকের সাথে প্রশ্নের কোডটিকে কেবল প্রতিলিপি করে। এটি এখনও তার সীমানা যাচাইয়ের জন্য ওপির হাতে থাকবে।
সোভিয়েট

1
.get (id = random_index) এর পরিবর্তে .filter (id__gte = random_index) ব্যবহার করা ভাল না [0: 1]? প্রথমত, এটি অবিচ্ছিন্ন pks দিয়ে সমস্যা সমাধানে সহায়তা করে। দ্বিতীয়ত, get_query_set ফিরে আসা উচিত ... একটি ক্যোয়ারীসেট। এবং আপনার উদাহরণে, এটি না।
নিকোলাস ডুমাজেট

2
আমি কেবল একটি পদ্ধতিতে নতুন ম্যানেজার তৈরি করব না। আমি ডিফল্ট ম্যানেজারে "get_random" যুক্ত করব যাতে আপনার এলোমেলো চিত্রের প্রয়োজন হলে আপনাকে সমস্ত () [0] হুপ দিয়ে যেতে হবে না। তদ্ব্যতীত, লেখক যদি কোনও ব্যবহারকারীর মডেলের ফরেনকি হন তবে আপনি user.painting_set.get_random () বলতে পারেন।
অ্যান্টি রসিনেন

এলোমেলো রেকর্ডগুলির তালিকা পাওয়ার মতো কম্বল অ্যাকশন চাইলে আমি সাধারণত একটি নতুন পরিচালক তৈরি করি। আমি ডিফল্ট ম্যানেজারে একটি পদ্ধতি তৈরি করব যদি আমি ইতিমধ্যে আমার রেকর্ডগুলি নিয়ে আরও নির্দিষ্ট কোনও কাজ করতাম।
সোভিয়েট

6

অন্যান্য উত্তরগুলি হয় সম্ভাব্য ধীর (ব্যবহার করে order_by('?')) বা একাধিক এসকিউএল কোয়েরি ব্যবহার করে। বিনা অর্ডার এবং একটি মাত্র ক্যোয়ারী (পোস্টগ্রিস ধরে ধরে) সহ একটি নমুনা সমাধান এখানে:

Model.objects.raw('''
    select * from {0} limit 1
    offset floor(random() * (select count(*) from {0}))
'''.format(Model._meta.db_table))[0]

সচেতন থাকুন যে টেবিলটি খালি থাকলে এটি সূচক ত্রুটি বাড়িয়ে তুলবে। এটি পরীক্ষা করার জন্য নিজেকে একটি মডেল-অজোনস্টিক সহায়ক ফাংশন লিখুন।


ধারণার একটি দুর্দান্ত প্রমাণ, তবে এটি ডাটাবেসের অভ্যন্তরে দুটি ক্যোয়ারী, আপনি যা সংরক্ষণ করেন তা হ'ল ডাটাবেসের একটি রাউন্ড্রিপ। এটির কাঁচা ক্যোয়ারী লেখার জন্য এবং এটি বজায় রাখার জন্য আপনাকে এটিকে অনেক বার চালিত করতে হবে। এবং যদি আপনি খালি টেবিলগুলি থেকে রক্ষা করতে চান তবে আপনি count()সম্ভবত আগাম চালাতে পারেন এবং কাঁচা কোয়েরিটি দিয়েছিলেন।
এন্ড্রে উভয়ই

2

আমি কীভাবে এটি করি তা কেবল একটি সহজ ধারণা:

def _get_random_service(self, professional):
    services = Service.objects.filter(professional=professional)
    i = randint(0, services.count()-1)
    return services[i]

1

কেবলমাত্র একটি (মোটামুটি সাধারণ) বিশেষ কেসটি লক্ষ করার জন্য, যদি কোনও মোছা ছাড়াই টেবিলে কোনও সূচকযুক্ত অটো-ইনক্রিমেন্ট কলাম থাকে, তবে এলোমেলো নির্বাচন করার সর্বোত্তম উপায়টি এমন একটি কোয়েরি:

SELECT * FROM table WHERE id = RAND() LIMIT 1

এটি টেবিলে আইডি নামের একটি কলাম ধরে। জ্যাঙ্গোতে আপনি এটি করতে পারেন:

Painting.objects.raw('SELECT * FROM appname_painting WHERE id = RAND() LIMIT 1')

যাতে আপনাকে অবশ্যই আপনার অ্যাপ্লিকেশন নামের সাথে অ্যাপ্লিকেশনটি প্রতিস্থাপন করতে হবে।

সাধারণভাবে, একটি আইডি কলাম সহ, অর্ডার_বি ('?') এর সাহায্যে আরও দ্রুত করা যায়:

Paiting.objects.raw(
        'SELECT * FROM auth_user WHERE id>=RAND() * (SELECT MAX(id) FROM auth_user) LIMIT %d' 
    % needed_count)

1

এটি উচ্চমাত্রায় পুনরুদ্ধারযোগ্য একটি সম্পর্কিত ডেটাবেস থেকে এলোমেলো সারি পাওয়া

কারণ জাজানো ওআরএম ব্যবহার করে এরকম কোনও কাজ করা আপনার ডিবি সার্ভারকে বিশেষভাবে রাগান্বিত করবে যদি আপনার কাছে বড় ডেটা টেবিল থাকে: |

এবং সমাধানটি একটি মডেল ম্যানেজার সরবরাহ করে এবং এসকিউএল কোয়েরিটি হাতে লিখে লিখুন;)

আপডেট :

আর একটি সমাধান যা কোনও ডাটাবেস ব্যাকএন্ডেও কাজ করে এমনকি কাস্টম না লিখেও অন-রিল্ড হয় ModelManagerজ্যাঙ্গোর একটি ক্যুরিসেট থেকে র্যান্ডম অবজেক্টগুলি পাওয়া


1

আপনি যে কোনও পুনরাবৃত্তিকে নমুনা করতে ব্যবহার করতে চান একই পন্থাটি আপনি ব্যবহার করতে চাইতে পারেন , বিশেষত যদি আপনি কোনও নমুনা সেট তৈরি করতে একাধিক আইটেমের নমুনা তৈরির পরিকল্পনা করেন । @ মাটিজনপিটার এবং @ ডিজনএক্স এতে অনেক চিন্তাভাবনা করেছে:

def random_sampling(qs, N=1):
    """Sample any iterable (like a Django QuerySet) to retrieve N random elements

    Arguments:
      qs (iterable): Any iterable (like a Django QuerySet)
      N (int): Number of samples to retrieve at random from the iterable

    References:
      @DZinX:  https://stackoverflow.com/a/12583436/623735
      @MartinPieters: https://stackoverflow.com/a/12581484/623735
    """
    samples = []
    iterator = iter(qs)
    # Get the first `N` elements and put them in your results list to preallocate memory
    try:
        for _ in xrange(N):
            samples.append(iterator.next())
    except StopIteration:
        raise ValueError("N, the number of reuested samples, is larger than the length of the iterable.")
    random.shuffle(samples)  # Randomize your list of N objects
    # Now replace each element by a truly random sample
    for i, v in enumerate(qs, N):
        r = random.randint(0, i)
        if r < N:
            samples[r] = v  # at a decreasing rate, replace random items
    return samples

মাটিজন এবং ডিএক্সিনএক্স এর সমাধান ডেটা সেটগুলির জন্য যা কোনও এলোমেলো অ্যাক্সেস সরবরাহ করে না। যে ডেটা সেট করে (এবং এসকিউএল এটি করে OFFSET) এর জন্য এটি অকারণে অক্ষম।
এন্ড্রে উভয়ই

পছন্দ করুন আমি কেবল ডেটা উত্স নির্বিশেষে একই পদ্ধতির ব্যবহারের কোডিং "দক্ষতা" পছন্দ করি। কখনও কখনও ডেটা স্যাম্পলিং দক্ষতা অন্যান্য প্রক্রিয়া দ্বারা সীমাবদ্ধ পাইপলাইন এর কার্যকারিতা উল্লেখযোগ্যভাবে প্রভাবিত করে না (এমএল প্রশিক্ষণের মতো আপনি ডেটা দিয়ে যা করছেন বাস্তবে)।
hobs

1

এর পক্ষে আরও একটি সহজ পদ্ধতির অন্তর্ভুক্ত রয়েছে কেবলমাত্র আগ্রহের রেকর্ডসেটে ফিল্টারিং এবং আপনার পছন্দমতো random.sampleনির্বাচন করতে ব্যবহার করা:

from myapp.models import MyModel
import random

my_queryset = MyModel.objects.filter(criteria=True)  # Returns a QuerySet
my_object = random.sample(my_queryset, 1)  # get a single random element from my_queryset
my_objects = random.sample(my_queryset, 5)  # get five random elements from my_queryset

মনে রাখবেন যে my_querysetখালি নয় তা যাচাই করার জন্য আপনার কাছে কিছু কোড থাকা উচিত ; যদি প্রথম যুক্তিতে খুব কম উপাদান থাকে তবে random.sampleফেরত ValueError: sample larger than populationদেয়।


2
এর ফলে কি পুরো ক্যোয়ারী পুনরুদ্ধার করা হবে?
পেরোহুন্টার

@perrohunter এটি এমনকি Querysetকমপক্ষে পাইথন ৩. 3. এবং জাজানো ২.১ এর সাথেও কাজ করবে না ; আপনাকে প্রথমে এটি একটি তালিকায় রূপান্তর করতে হবে, যা স্পষ্টতই পুরো ক্যোরিসেটটি পুনরুদ্ধার করে।
এন্ড্রে উভয়ই

@ এন্ড্রেবোথ - এটি ২০১ 2016 সালে লেখা হয়েছিল, যখন তাদের কেউই ছিল না।
একনাল

এজন্য আমি সংস্করণ তথ্য যুক্ত করেছি। তবে যদি এটি 2016 সালে কাজ করে তবে এটি পুরো ক্যোয়ারসেটটিকে একটি তালিকায় টানিয়ে দিয়েছিল তাই না?
এন্ড্রে উভয়ই

পছন্দ করুন
ekkanal

1

হাই, আমাকে এমন একটি ক্যোরিসেট থেকে এলোমেলো রেকর্ড নির্বাচন করতে হবে যার দৈর্ঘ্য আমারও জানা উচিত (যেমন ওয়েব পৃষ্ঠায় বর্ণিত আইটেম উত্পাদিত হয়েছে এবং রেকর্ড রেখে গেছে)

q = Entity.objects.filter(attribute_value='this or that')
item_count = q.count()
random_item = q[random.randomint(1,item_count+1)]

অর্ধেক সময় ধরে (0.7s বনাম 1.7s) লেগেছিল:

item_count = q.count()
random_item = random.choice(q)

আমি অনুমান করছি এটি এলোমেলো এন্ট্রি নির্বাচন করার আগে পুরো ক্যোয়ারীটি টানতে এড়াতে এবং আমার সিস্টেমকে এমন একটি পৃষ্ঠার পক্ষে যথেষ্ট প্রতিক্রিয়াশীল করে তুলেছে যা বারবার অ্যাক্সেস করা একটি পুনরাবৃত্ত টাস্কের জন্য ব্যবহারকারীরা আইটেম_কাউন্ট গণনা দেখতে চায়।


0

কোনও মুছা ছাড়াই প্রাথমিক কী স্বতঃবৃদ্ধি করার পদ্ধতি

আপনার যদি এমন কোনও টেবিল থাকে যেখানে প্রাথমিক কীটি কোনও ফাঁক ছাড়াই অনুক্রমিক পূর্ণসংখ্যা হয়, তবে নিম্নলিখিত পদ্ধতির কাজ করা উচিত:

import random
max_id = MyModel.objects.last().id
random_id = random.randint(0, max_id)
random_obj = MyModel.objects.get(pk=random_id)

এই পদ্ধতিটি এখানে অন্যান্য পদ্ধতির তুলনায় অনেক বেশি দক্ষ যা টেবিলের সমস্ত সারি দিয়ে পুনরাবৃত্তি করে। যদিও এটিতে দুটি ডাটাবেস ক্যোয়ার দরকার হয়, উভয়ই তুচ্ছ। তদতিরিক্ত, এটি সহজ এবং কোনও অতিরিক্ত ক্লাস সংজ্ঞায়িত করার প্রয়োজন নেই। তবে এটির প্রয়োগযোগ্যতা স্বয়ংক্রিয়-বৃদ্ধিকারী প্রাথমিক কী সহ সারণীতে সীমাবদ্ধ যেখানে সারিগুলি কখনই মোছেনি, যেমন আইডির ক্রমের কোনও ফাঁক নেই।

যে ক্ষেত্রে সারিগুলি শূন্যস্থানগুলি যেমন মুছে ফেলা হয়েছে তা মুছে ফেলা হয়েছে, বিদ্যমান প্রাথমিক কীটি এলোমেলোভাবে নির্বাচন না করা পর্যন্ত যদি এটি পুনরায় চেষ্টা করা হয় তবে এই পদ্ধতিটি এখনও কাজ করতে পারে।

তথ্যসূত্র


0

আমি খুব সহজ সমাধান পেয়েছি, কাস্টম ম্যানেজার করুন:

class RandomManager(models.Manager):
    def random(self):
        return random.choice(self.all())

এবং তারপরে মডেলটিতে যুক্ত করুন:

class Example(models.Model):
    name = models.CharField(max_length=128)
    objects = RandomManager()

এখন, আপনি এটি ব্যবহার করতে পারেন:

Example.objects.random()

এলোমেলো আমদানি পছন্দ থেকে
অ্যাডাম স্টারহ

3
আপনি যদি গতি চান তবে দয়া করে এই পদ্ধতিটি ব্যবহার করবেন না। এই সমাধানটি খুব ধীর। আমি চেক করেছি. এটি order_by('?').first()60 বারেরও বেশি ধীর er
ল্যাগরেঞ্জ

@ অ্যালেক্স 78191 না, "?" খুব খারাপ, কিন্তু আমার পদ্ধতি এক্সট্রা ধীর। আমি শীর্ষ উত্তর সমাধান ব্যবহার করেছি।
ল্যাগরেঞ্জ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.