জ্যাঙ্গো ভিউতে কীভাবে দুটি বা আরও প্রশ্নের সন্ধান করা হবে?


653

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

আমি এটা কিভাবে করবো? আমি এটি চেষ্টা করেছি:

result_list = []            
page_list = Page.objects.filter(
    Q(title__icontains=cleaned_search_term) | 
    Q(body__icontains=cleaned_search_term))
article_list = Article.objects.filter(
    Q(title__icontains=cleaned_search_term) | 
    Q(body__icontains=cleaned_search_term) | 
    Q(tags__icontains=cleaned_search_term))
post_list = Post.objects.filter(
    Q(title__icontains=cleaned_search_term) | 
    Q(body__icontains=cleaned_search_term) | 
    Q(tags__icontains=cleaned_search_term))

for x in page_list:
    result_list.append(x)
for x in article_list:
    result_list.append(x)
for x in post_list:
    result_list.append(x)

return object_list(
    request, 
    queryset=result_list, 
    template_object_name='result',
    paginate_by=10, 
    extra_context={
        'search_term': search_term},
    template_name="search/result_list.html")

তবে এটি কাজ করে না। আমি জেনেরিক ভিউতে সেই তালিকাটি ব্যবহার করার চেষ্টা করার পরে আমি একটি ত্রুটি পাই। তালিকায় ক্লোন বিশিষ্টটি অনুপস্থিত।

কেউ কি জানেন যে আমি কীভাবে তিনটি তালিকার একত্রীকরণ করতে পারি page_list, article_listএবং post_list?


দেখে মনে হচ্ছে t_rybik djangosnippets.org/snippets/1933
আকাইহোলা

অনুসন্ধানের জন্য হাইস্ট্যাকের মতো নিবেদিত সমাধানগুলি ব্যবহার করা আরও ভাল - এটি খুব নমনীয়।
তত্ত্বাবধান

1
জ্যাঙ্গো ব্যবহারকারীরা 1.11 এবং এভিভি, এই উত্তরটি দেখুন - stackoverflow.com/a/42186970/6003362
সাহিল আগরওয়াল

দ্রষ্টব্য : প্রশ্নটি খুব বিরল ক্ষেত্রে সীমাবদ্ধ থাকে যখন 3 বিভিন্ন মডেল একসাথে একত্রিত করার পরে ধরণের ডেটা আলাদা করার জন্য আপনাকে আবার তালিকাতে মডেলগুলি বের করার প্রয়োজন হয় না। বেশিরভাগ ক্ষেত্রে - যদি পার্থক্য আশা করা হয় - এটি ইন্টারফেসকে ভুল করবে। একই মডেলের জন্য: সম্পর্কে উত্তর দেখুন union
সাওওমির লেনার্ট

উত্তর:


1058

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

from itertools import chain
result_list = list(chain(page_list, article_list, post_list))

itertools.chainপ্রতিটি তালিকার লুপিং এবং উপাদানগুলিকে একে একে যুক্ত করার চেয়ে দ্রুত ব্যবহার করা, যেহেতু itertoolsসি তে প্রয়োগ করা হয় এটি প্রতিটি ক্যোয়ারসেটকে কনটেটেটিংয়ের আগে তালিকায় রূপান্তরিত করার চেয়ে কম মেমোরি খরচ করে।

এখন ফলাফলের তালিকাটি বাছাই করা সম্ভব যেমন তারিখ অনুসারে (অন্য উত্তরে হেসেন জে এর মন্তব্যে অনুরোধ করা হয়েছে)। sorted()ফাংশন সুবিধামত জেনারেটরের গ্রহণ করে এবং একটি তালিকা ফেরৎ:

result_list = sorted(
    chain(page_list, article_list, post_list),
    key=lambda instance: instance.date_created)

যদি আপনি পাইথন ২.৪ বা attrgetterতার বেশি ব্যবহার করেন তবে আপনি ল্যাম্বদার পরিবর্তে ব্যবহার করতে পারেন । আমি এটির দ্রুত পড়া সম্পর্কে মনে করি, তবে মিলিয়ন আইটেম তালিকার জন্য আমি লক্ষ্যণীয় গতির পার্থক্যটি দেখতে পাই নি।

from operator import attrgetter
result_list = sorted(
    chain(page_list, article_list, post_list),
    key=attrgetter('date_created'))

13
যদি ওআর ক্যোয়ারী সম্পাদন করতে একই টেবিল থেকে ক্যোসিকেটগুলি মার্জ করে এবং নকল সারি থাকে তবে আপনি তাদের গ্রুপপ্লে ফাংশন দিয়ে মুছে ফেলতে পারেন: from itertools import groupby unique_results = [rows.next() for (key, rows) in groupby(result_list, key=lambda obj: obj.id)]
জোশ রুসো

1
ঠিক আছে, এই প্রসঙ্গে গ্রুপবিধি সম্পর্কে ফাংশন সম্পর্কে এনএম। কিউ ফাংশনটির সাহায্যে আপনার যে কোনও ওআর ক্যোয়ারী আপনার প্রয়োজন হতে পারে: https://docs.djangoproject.com/en/1.3/topics/db/queries/#complex-lookups-with-q-objects
জোশ রুসো

2
@apelliciari চেইন list.extend এর তুলনায় উল্লেখযোগ্যভাবে কম মেমরি ব্যবহার করে, কারণ এটি উভয় তালিকা সম্পূর্ণরূপে মেমরিতে লোড করার দরকার নেই।
ড্যান গেইল

2
@ অরাইটাইভ এখানে এই লিঙ্কটির নতুন সংস্করণটি রয়েছে: ডকস.ডজ্যাঙ্গোপ্রজেক্ট /en/1.8/topics/db/queries/…
জোশ রুসো

1
এই পদ্ধতির চেষ্টা করেও দেখুন'list' object has no attribute 'complex_filter'
গ্রিলাজ

466

এটা চেষ্টা কর:

matches = pages | articles | posts

এটি ক্যোরিসেটগুলির সমস্ত ফাংশন ধরে রাখে যা আপনি চাইলে order_byবা অনুরূপ চাইলে দুর্দান্ত ।

দয়া করে নোট করুন: এটি দুটি ভিন্ন মডেলের ক্যোয়ারসেটে কাজ করে না।


10
কাটা ক্যোয়ারসেটগুলিতে কাজ করে না, যদিও। নাকি আমি কিছু মিস করছি?
sthzg

1
আমি "|" ব্যবহার করে ক্যোয়ারেটগুলিতে যোগ দিতাম কিন্তু সবসময় ঠিক কাজ করে না। "কিউ" ব্যবহার করা আরও ভাল: ডকস.ডজ্যাঙ্গোপ্রজেক্ট
ইগনাসিও পেরেজ

1
জ্যাঙ্গো 1.6 ব্যবহার করে এটি নকল তৈরি করে বলে মনে হচ্ছে না।
তেখিন

15
এখানে |সেট ইউনিয়ন অপারেটর, বিটওয়াইড OR নয়।
e100

6
@ e100 না, এটি সেট ইউনিয়ন অপারেটর নয়। জ্যাঙ্গো
শ্যাঙ্গজিয়াও

109

সম্পর্কিত, একই মডেল থেকে ক্যোয়ারেটগুলি মিশ্রণের জন্য, বা কয়েকটি মডেল থেকে অনুরূপ ক্ষেত্রগুলির জন্য, জ্যাঙ্গো 1.11 দিয়ে শুরু করে একটি qs.union()পদ্ধতিও পাওয়া যায়:

union()

union(*other_qs, all=False)

জ্যাঙ্গো 1.11 এ নতুন । দুটি বা ততোধিক কোয়েরীসেটের ফলাফল একত্রিত করতে এসকিউএল এর ইউনিয়ন অপারেটর ব্যবহার করে। উদাহরণ স্বরূপ:

>>> qs1.union(qs2, qs3)

ইউনিয়ন অপারেটর ডিফল্টরূপে কেবল স্বতন্ত্র মান নির্বাচন করে। সদৃশ মানগুলিকে অনুমতি দেওয়ার জন্য, সমস্ত = সত্য যুক্তি ব্যবহার করুন।

ইউনিয়ন (), ছেদ (), এবং পার্থক্য () প্রথম ক্যোয়ারীসেটের ধরণের রিটার্ন মডেল উদাহরণগুলি এমনকি অন্য মডেলগুলির কোয়েরিसेटস হলেও if সমস্ত মডেলগুলি পাস করা যতক্ষণ না সমস্ত ক্যোরিসেটগুলিতে (যেমন কমপক্ষে প্রকারগুলি, নামগুলি ততক্ষণ ক্রমযুক্ত না হয় ততক্ষণ পর্যন্ত গুরুত্বপূর্ণ নয়) যতক্ষণ না সেগুলির তালিকা একই থাকে works

তদতিরিক্ত, ফলাফলের ক্যোরিসেটে কেবলমাত্র সীমাবদ্ধ, অফসেট এবং অর্ডার বাই (যেমন স্লাইসিং এবং অর্ডার_বি ()) অনুমোদিত। তদ্ব্যতীত, ডাটাবেসগুলি সম্মিলিত ক্যোয়ারিতে কী কী অপারেশন অনুমোদিত তা নিয়ে সীমাবদ্ধতা রাখে। উদাহরণস্বরূপ, বেশিরভাগ ডাটাবেসগুলি সম্মিলিত ক্যোয়ারিতে LIMIT বা অফসেটের অনুমতি দেয় না।

https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.union


এটি আমার সমস্যা সেটটির জন্য আরও ভাল সমাধান যা অনন্য মান থাকতে হবে।
স্ফটিকগুলি পোড়ানো

জিওডজ্যাঙ্গো জ্যামিতির জন্য কাজ করে না।
মারম্যাট

আপনি কোথা থেকে ইউনিয়ন আমদানি করবেন? এটি কি ক্যোয়ারসেটের এক্স নম্বরগুলির মধ্যে একটি থেকে আসতে হবে?
জ্যাক

হ্যাঁ, এটি ক্যোরিসেটের একটি পদ্ধতি।
উদি

আমি মনে করি এটি অনুসন্ধান ফিল্টারগুলি সরিয়ে ফেলেছে
পিয়েরে কর্ডিয়ার

76

আপনি QuerySetChainনীচের ক্লাস ব্যবহার করতে পারেন । জ্যাঙ্গোর প্যাগিনেটারের সাথে এটি ব্যবহার করার সময়, কেবলমাত্র COUNT(*)সমস্ত ক্যোয়ারসেটের অনুসন্ধান এবং SELECT()ক্যোয়ারসেটগুলির জন্য অনুসন্ধানগুলির জন্য ডাটাবেসগুলিকে কেবল হিট করা উচিত যাদের রেকর্ড বর্তমান পৃষ্ঠায় প্রদর্শিত হয়।

নোট করুন যে জেনেরিক ভিউ সহ template_name=একটি QuerySetChainজেনারেল ভিউ ব্যবহার করা হচ্ছে কিনা তা নির্দিষ্ট করতে হবে , এমনকি শিকলযুক্ত ক্যোয়ারসেটগুলি সমস্ত একই মডেল ব্যবহার করে use

from itertools import islice, chain

class QuerySetChain(object):
    """
    Chains multiple subquerysets (possibly of different models) and behaves as
    one queryset.  Supports minimal methods needed for use with
    django.core.paginator.
    """

    def __init__(self, *subquerysets):
        self.querysets = subquerysets

    def count(self):
        """
        Performs a .count() for all subquerysets and returns the number of
        records as an integer.
        """
        return sum(qs.count() for qs in self.querysets)

    def _clone(self):
        "Returns a clone of this queryset chain"
        return self.__class__(*self.querysets)

    def _all(self):
        "Iterates records in all subquerysets"
        return chain(*self.querysets)

    def __getitem__(self, ndx):
        """
        Retrieves an item or slice from the chained set of results from all
        subquerysets.
        """
        if type(ndx) is slice:
            return list(islice(self._all(), ndx.start, ndx.stop, ndx.step or 1))
        else:
            return islice(self._all(), ndx, ndx+1).next()

আপনার উদাহরণে, ব্যবহারটি হবে:

pages = Page.objects.filter(Q(title__icontains=cleaned_search_term) |
                            Q(body__icontains=cleaned_search_term))
articles = Article.objects.filter(Q(title__icontains=cleaned_search_term) |
                                  Q(body__icontains=cleaned_search_term) |
                                  Q(tags__icontains=cleaned_search_term))
posts = Post.objects.filter(Q(title__icontains=cleaned_search_term) |
                            Q(body__icontains=cleaned_search_term) | 
                            Q(tags__icontains=cleaned_search_term))
matches = QuerySetChain(pages, articles, posts)

তারপরে matchesআপনি result_listযেমন উদাহরণ হিসাবে ব্যবহার করেছিলেন তেমন প্যাগেইনেটর ব্যবহার করুন।

itertoolsমডিউল পাইথন 2.3 চালু হয়, তাই এটি সব পাইথন সংস্করণ জ্যাঙ্গো উপর সঞ্চালিত হয় যা পাওয়া উচিত।


5
চমৎকার পদ্ধতির, তবে একটি সমস্যা যা আমি এখানে দেখছি তা হল ক্যোরি সেটগুলি "মাথার টু লেজ" যুক্ত করা হয়। যদি প্রতিটি ক্যোয়ারসেট তারিখ অনুসারে অর্ডার করা হয় এবং তারিখ অনুসারে একের জন্য সংযুক্ত-সেটটি প্রয়োজন হয় তবে কী হবে?
হেসেন

এটি অবশ্যই আশাব্যঞ্জক দেখায়, দুর্দান্ত, আমাকে এটি চেষ্টা করতে হবে তবে আজ আমার কাছে সময় নেই। এটি যদি আমার সমস্যার সমাধান করে তবে আমি আপনার কাছে ফিরে আসব। মহান কাজ.
espenhogbakk

ঠিক আছে, আমাকে আজ চেষ্টা করতে হয়েছিল, তবে এটি কার্যকর হয়নি, প্রথমে এটি অভিযোগ করেছিল যে এটির জন্য _ক্লোন বৈশিষ্ট্য নেই তাই আমি যুক্ত করেছিলাম যে, কেবলমাত্র সমস্ত_এটি অনুলিপি করা হয়েছে এবং এটি কাজ করেছে, তবে মনে হয় যে এই ক্যোরিসেটটিতে প্যাগেইনেটরটির কিছু সমস্যা আছে। আমি এই প্যাগিনেটার ত্রুটিটি পেয়েছি: "আনসাইজড অবজেক্টের লেন ()"
এস্পেনহগব্যাক্ক

1
@ এসপেন পাইথন লাইব্রেরি: পিডিবি, লগিং। বাহ্যিক: আইপিথন, আইপিডিবি, জাঙ্গো-লগিং, জ্যাঞ্জো-ডিবাগ-সরঞ্জামদণ্ড, জ্যাঙ্গো-কমান্ড-এক্সটেনশনস, ওয়ার্কজেগ। কোডে মুদ্রণ বিবৃতি ব্যবহার করুন বা লগিং মডিউলটি ব্যবহার করুন। সর্বোপরি, শেলটিতে আত্মনিবেশ করা শিখুন। ডিবাগিং জ্যাঙ্গো সম্পর্কে ব্লগ পোস্টের জন্য গুগল। সাহায্য করে আনন্দ পেলাম!
আকাইহোলা


27

আপনার বর্তমান পদ্ধতির বড় ক্ষতিটি হ'ল বিশাল অনুসন্ধান ফলাফলের সেটগুলির সাথে তার অদক্ষতা, কারণ আপনি কেবলমাত্র ফলাফলের একটি পৃষ্ঠার প্রদর্শন করার ইচ্ছুক হলেও আপনাকে প্রতিবার ডাটাবেস থেকে পুরো ফলাফল সেটটি নীচে টানতে হবে।

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

আপনার তিনটি মডেলের শিরোনাম এবং দেহের ক্ষেত্র রয়েছে তা প্রদত্ত, কেন মডেল উত্তরাধিকার ব্যবহার করবেন না ? কেবলমাত্র তিনটি মডেলই কোনও সাধারণ পূর্বপুরুষের শিরোনাম এবং শরীরে উত্তরাধিকারী হোন এবং পূর্বপুরুষের মডেলটিতে একক ক্যোয়ারী হিসাবে অনুসন্ধান করুন।


23

আপনি যদি অনেকগুলি প্রশ্নের সন্ধান করতে চান তবে এটি চেষ্টা করুন:

from itertools import chain
result = list(chain(*docs))

যেখানে: ডক্স হল ক্যোয়ারসেটগুলির একটি তালিকা



8

এটি দুটি উপায়েও অর্জন করা যেতে পারে।

এটি করার 1 ম উপায়

|দুটি ক্যোয়ারসেটের ইউনিয়ন নিতে ক্যোরিসেটের জন্য ইউনিয়ন অপারেটর ব্যবহার করুন । উভয় ক্যোয়ারসেট ইউনিয়ন অপারেটর ব্যবহার করে ক্যোয়ারসেটগুলি একত্রিত করা সম্ভবের চেয়ে একই মডেল / একক মডেলের অন্তর্ভুক্ত।

একটি উদাহরণ জন্য

pagelist1 = Page.objects.filter(
    Q(title__icontains=cleaned_search_term) | 
    Q(body__icontains=cleaned_search_term))
pagelist2 = Page.objects.filter(
    Q(title__icontains=cleaned_search_term) | 
    Q(body__icontains=cleaned_search_term))
combined_list = pagelist1 | pagelist2 # this would take union of two querysets

এটি করার 2 য় উপায়

দুটি ক্যোয়ারসেটের মধ্যে সম্মিলন অপারেশন অর্জনের অন্য একটি উপায় হ'ল ইটারটুলস চেইন ফাংশন ব্যবহার করা ।

from itertools import chain
combined_results = list(chain(pagelist1, pagelist2))

7

প্রয়োজনীয়তা: Django==2.0.2 ,django-querysetsequence==0.8

আপনি যদি একত্রিত করতে চান querysetsএবং এখনও একটি নিয়ে বেরিয়ে আসতে QuerySetচান তবে আপনি জ্যাঙ্গো-ক্যোরিসেট-সিকোয়েন্সটি পরীক্ষা করে দেখতে চাইতে পারেন ।

তবে এটি সম্পর্কে একটি নোট। এটি querysetsযুক্তি হিসাবে এটি কেবল দুটি লাগে । তবে অজগর দিয়ে reduceআপনি সর্বদা এটি একাধিক querysetস প্রয়োগ করতে পারেন ।

from functools import reduce
from queryset_sequence import QuerySetSequence

combined_queryset = reduce(QuerySetSequence, list_of_queryset)

এবং এটাই. নীচে একটি অবস্থা আমি গাড়ীতে আঘাত এবং আমি কিভাবে নিযুক্ত list comprehension, reduceএবংdjango-queryset-sequence

from functools import reduce
from django.shortcuts import render    
from queryset_sequence import QuerySetSequence

class People(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    mentor = models.ForeignKey('self', null=True, on_delete=models.SET_NULL, related_name='my_mentees')

class Book(models.Model):
    name = models.CharField(max_length=20)
    owner = models.ForeignKey(Student, on_delete=models.CASCADE)

# as a mentor, I want to see all the books owned by all my mentees in one view.
def mentee_books(request):
    template = "my_mentee_books.html"
    mentor = People.objects.get(user=request.user)
    my_mentees = mentor.my_mentees.all() # returns QuerySet of all my mentees
    mentee_books = reduce(QuerySetSequence, [each.book_set.all() for each in my_mentees])

    return render(request, template, {'mentee_books' : mentee_books})

1
না Book.objects.filter(owner__mentor=mentor)একই জিনিস করে না? আমি নিশ্চিত নই যে এটি একটি বৈধ ব্যবহারের ক্ষেত্রে। আমি মনে করি এরকম কিছু করা শুরু করার আগে আপনার Bookএকাধিক ownerগুলি প্রয়োজন হতে পারে ।
এস

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

6

এখানে একটি ধারণা রয়েছে ... তিনটির প্রত্যেকের থেকে ফলাফলের একটি সম্পূর্ণ পৃষ্ঠা নীচে টানুন এবং তারপরে ২০ টি কমপক্ষে দরকারী দরকারীগুলি ফেলে দিন ... এটি বৃহত্তর ক্যোয়ারসেটগুলি সরিয়ে দেয় এবং এইভাবে আপনি কেবলমাত্র প্রচুর পরিবর্তে কিছুটা পারফরম্যান্স ত্যাগ করতে পারেন



-1

এই পুনরাবৃত্ত ফাংশনটি একটি ক্যোয়ারসেটে ক্যোরিসেটের অ্যারে সংযুক্ত করে।

def merge_query(ar):
    if len(ar) ==0:
        return [ar]
    while len(ar)>1:
        tmp=ar[0] | ar[1]
        ar[0]=tmp
        ar.pop(1)
        return ar

1
আমি আক্ষরিক অর্থেই হারিয়েছি।
লাইকুইড

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