জ্যাঙ্গো ফিল্টার ক্যোরিসেট __in তালিকায় প্রতিটি * আইটেমের জন্য __in


105

ধরা যাক আমার কাছে নিম্নলিখিত মডেলগুলি রয়েছে

class Photo(models.Model):
    tags = models.ManyToManyField(Tag)

class Tag(models.Model):
    name = models.CharField(max_length=50)

একটি দৃশ্যে আমার কাছে বিভাগগুলির নামক একটিভ ফিল্টার সহ একটি তালিকা রয়েছে । আমি ফটো অবজেক্টগুলিকে ফিল্টার করতে চাই যার বিভাগে সমস্ত ট্যাগ রয়েছে ।

আমি চেষ্টা করেছিলাম:

Photo.objects.filter(tags__name__in=categories)

তবে এটি বিভাগের কোনও আইটেমের সাথে মেলে , সমস্ত আইটেম নয়।

সুতরাং বিভাগগুলি যদি ['হলিডে', 'গ্রীষ্ম' হয় তবে আমি একটি ছুটির দিন এবং গ্রীষ্মের ট্যাগ উভয়ের সাথেই ফটো চাই।

এটি কি অর্জন করা যায়?


7
হতে পারে: qs = Photo.objects.all (); বিভাগে বিভাগের জন্য: qs = qs.filter (ট্যাগ__ নাম = বিভাগ)
jpic

4
jpic ঠিক আছে, Photo.objects.filter(tags__name='holiday').filter(tags__name='summer')যাওয়ার উপায়। (এটি jpic এর উদাহরণ হিসাবে একই)। প্রত্যেকের ক্যোয়ারিতে filterআরও JOINগুলি যুক্ত করা উচিত , যাতে তারা খুব বেশি হয় তবে আপনি টীকাটি গ্রহণ করতে পারেন ।
লভিক

4
দস্তাবেজগুলিতে এখানে উল্লেখ রয়েছে: ডকস.ডজ্যাঙ্গোপ্রজেক্ট
এএন

উত্তর:


127

সারসংক্ষেপ:

একটি বিকল্প হ'ল, .filter()প্রতিটি বিভাগের জন্য যোগ করার জন্য মন্তব্যে জেপিক এবং সাগলেনের পরামর্শ অনুসারে । প্রতিটি অতিরিক্ত filterআরও যোগ দেয়, যা বিভাগের ছোট সেটগুলির জন্য সমস্যা হওয়া উচিত নয়।

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

আপনার কাছে কাস্টম প্রশ্নগুলি ব্যবহার করার বিকল্প রয়েছে ।


কিছু উদাহরণ

পরীক্ষা সেটআপ:

class Photo(models.Model):
    tags = models.ManyToManyField('Tag')

class Tag(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

In [2]: t1 = Tag.objects.create(name='holiday')
In [3]: t2 = Tag.objects.create(name='summer')
In [4]: p = Photo.objects.create()
In [5]: p.tags.add(t1)
In [6]: p.tags.add(t2)
In [7]: p.tags.all()
Out[7]: [<Tag: holiday>, <Tag: summer>]

শৃঙ্খলিত ফিল্টারগুলির পদ্ধতির ব্যবহার :

In [8]: Photo.objects.filter(tags=t1).filter(tags=t2)
Out[8]: [<Photo: Photo object>]

ফলাফলের ফলাফল:

In [17]: print Photo.objects.filter(tags=t1).filter(tags=t2).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_photo_tags" T4 ON ("test_photo"."id" = T4."photo_id")
WHERE ("test_photo_tags"."tag_id" = 3  AND T4."tag_id" = 4 )

মনে রাখবেন যে, প্রতিটি filterআরো যোগ করে JOINSক্যোয়ারী করতে।

টিকা রচনা পদ্ধতির ব্যবহার :

In [29]: from django.db.models import Count
In [30]: Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2)
Out[30]: [<Photo: Photo object>]

ফলাফলের ফলাফল:

In [32]: print Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2).query
SELECT "test_photo"."id", COUNT("test_photo_tags"."tag_id") AS "num_tags"
FROM "test_photo"
LEFT OUTER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
WHERE ("test_photo_tags"."tag_id" IN (3, 4))
GROUP BY "test_photo"."id", "test_photo"."id"
HAVING COUNT("test_photo_tags"."tag_id") = 2

ANDএড Qঅবজেক্টগুলি কাজ করবে না:

In [9]: from django.db.models import Q
In [10]: Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
Out[10]: []
In [11]: from operator import and_
In [12]: Photo.objects.filter(reduce(and_, [Q(tags__name='holiday'), Q(tags__name='summer')]))
Out[12]: []

ফলাফলের ফলাফল:

In [25]: print Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer')).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_tag" ON ("test_photo_tags"."tag_id" = "test_tag"."id")
WHERE ("test_tag"."name" = holiday  AND "test_tag"."name" = summer )

6
একটি কাস্টম অনুসন্ধান সঙ্গে একটি সমাধান আছে? docs.djangoproject.com/en/1.10/howto/custom-lookups "__in" "" __ সমস্ত "এ স্যুইচ করা এবং এটির সঠিক স্কয়ার কোয়েরি তৈরি করতে শীতল হবে।
t1m0

4
এই টীকা সমাধানটি ভুল বলে মনে হচ্ছে। যদি সেখানে তিনটি ট্যাগের সম্ভাব্যতা থাকে (এর জন্য অতিরিক্ত একটি কল করতে দিন t3এবং একটি ফটোতে ট্যাগ রয়েছে t2এবং t3তারপরে এই ফটোটি প্রদত্ত প্রশ্নের সাথে মেলে
will

@ বারুই আমি মনে করি ধারণাটি হ'ল আপনি num_tags = 2 কে num_tags = len (ট্যাগ) দিয়ে প্রতিস্থাপন করবেন; আমি আশা করি হার্ড কোডিং 2 কেবল উদাহরণস্বরূপ ছিল।
tbm

4
@tbm এখনও এটি কাজ করবে না। Photo.objects.filter(tags__in=tags)যে কোনও ট্যাগ রয়েছে এমন ফটোগুলির সাথে মেলে, যা কেবল সমস্তই রয়েছে। কেবলমাত্র কাঙ্ক্ষিত ট্যাগগুলির মধ্যে একটিতে, আপনি যে ট্যাগটি খুঁজছেন ঠিক তার পরিমাণে থাকতে পারে এবং কিছুতে যে সমস্ত পছন্দসই ট্যাগ রয়েছে তাদের কয়েকটিতে অতিরিক্ত ট্যাগও থাকতে পারে।
বেরুয়িক

4
@ বিউরিক টীকাগুলি কোয়েরিতে ফিরে আসা ট্যাগগুলিকেই গণনা করে, তাই যদি (সংখ্যাটি কোয়েরিতে ফিরে আসে) == (সংখ্যা ট্যাগ অনুসন্ধান করা হয়) তবে সারিটি অন্তর্ভুক্ত করা হবে; "অতিরিক্ত" ট্যাগগুলি অনুসন্ধান করা হয় না, সুতরাং এটি গণনা করা হবে না। আমি এটি আমার নিজের অ্যাপের মধ্যে যাচাই করেছি।
tbm

8

আরেকটি পদ্ধতি যা কাজ করে, যদিও কেবল পোস্টগ্রিএসকিউএল, তা ব্যবহার করছে django.contrib.postgres.fields.ArrayField:

দস্তাবেজ থেকে অনুলিপি করা উদাহরণ :

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

>>> Post.objects.filter(tags__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__contains=['django'])
<QuerySet [<Post: First post>, <Post: Third post>]>

>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
<QuerySet [<Post: First post>]>

ArrayFieldওভারল্যাপ এবং সূচক রূপান্তরগুলির মতো আরও কিছু শক্তিশালী বৈশিষ্ট্য রয়েছে ।


3

এটি জ্যাঙ্গো ওআরএম এবং কিছু পাইথন ম্যাজিক ব্যবহার করে গতিশীল ক্যোয়ারী জেনারেশন দ্বারাও করা যেতে পারে :)

from operator import and_
from django.db.models import Q

categories = ['holiday', 'summer']
res = Photo.filter(reduce(and_, [Q(tags__name=c) for c in categories]))

প্রতিটি বিভাগের জন্য উপযুক্ত Q অবজেক্ট তৈরি করা এবং তারপরে এন্ড আর অপারেটরকে একটি কোয়েরিসেটে মিশ্রন করা ধারণা। যেমন আপনার উদাহরণস্বরূপ এটি সমান হবে

res = Photo.filter(Q(tags__name='holiday') & Q(tags__name='summer'))

4
এটি কাজ করবে না। আপনার প্রশ্নের উদাহরণগুলি প্রশ্নযুক্ত মডেলগুলির জন্য কোনও কিছুই ফেরত দেবে না।
Davor Lucic

সংশোধনের জন্য ধন্যবাদ। আমি ভেবেছিলাম শৃঙ্খলাকৃতি filterএকই andফিল্টারে কিউ অবজেক্টের জন্য ব্যবহারের সমান হবে ... আমার ভুল।
00

কোনও উদ্বেগ নেই, আমার প্রথম চিন্তা যেখানে প্রশ্নটিও রয়েছে।
লুভিক

4
আপনি যদি তুলনা করতে বড় টেবিল এবং বড় ডেটা নিয়ে কাজ করেন তবে আমরা আমাদের ধীর করব। (প্রতি 1 মিলিয়ন এর মতো)
gies0r

4
এই পদ্ধতির উচিত যদি আপনার কাছ থেকে সুইচ কাজ filterকরতে excludeহবে এবং একটি অস্বীকার অপারেটর ব্যবহার করেন। ভালো লেগেছে: res = Photo.exclude(~reduce(and_, [Q(tags__name=c) for c in categories]))
বেন

1

আমি একটি সামান্য ফাংশন ব্যবহার করি যা প্রদত্ত অপারেটরের জন্য একটি কলামের নামের জন্য তালিকার উপরে ফিল্টারগুলি পুনরাবৃত্তি করে:

def exclusive_in (cls,column,operator,value_list):         
    myfilter = column + '__' + operator
    query = cls.objects
    for value in value_list:
        query=query.filter(**{myfilter:value})
    return query  

এবং এই ফাংশনটিকে এর মতো বলা যেতে পারে:

exclusive_in(Photo,'tags__name','iexact',['holiday','summer'])

এটি তালিকার কোনও শ্রেণি এবং আরও ট্যাগগুলির সাথেও কাজ করে; অপারেটররা 'আইটেক্স্যাক্ট', 'ইন', 'রয়েছে', 'নে', ... এর মতো যে কেউ হতে পারে



-1

আমরা যদি এটি গতিশীলভাবে করতে চাই, উদাহরণ অনুসরণ করুন:

tag_ids = [t1.id, t2.id]
qs = Photo.objects.all()

for tag_id in tag_ids:
    qs = qs.filter(tag__id=tag_id)    

print qs

দ্বিতীয় পুনরাবৃত্তির সাথে সাথে কাজ করা যাবে না, ক্যোরিসেটটি খালি হবে
ল্যাপিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.