জ্যাঙ্গো কেবল নকল ক্ষেত্রের মান সহ সারি নির্বাচন করে


99

ধরুন আমাদের কাছে জ্যাঙ্গোতে একটি মডেল রয়েছে যা নিম্নলিখিত হিসাবে সংজ্ঞায়িত হয়েছে:

class Literal:
    name = models.CharField(...)
    ...

নাম ক্ষেত্রটি অনন্য নয় এবং এর ফলে সদৃশ মান থাকতে পারে। আমাকে নিম্নলিখিত কাজটি সম্পন্ন করতে হবে: মডেলের যে সমস্ত ক্ষেত্রটির কমপক্ষে একটির সদৃশ মান রয়েছে তার থেকে সমস্ত সারি নির্বাচন করুন name

আমি জানি কীভাবে এটি প্লেইন এসকিউএল (সর্বোত্তম সমাধান হতে পারে না) ব্যবহার করে:

select * from literal where name IN (
    select name from literal group by name having count((name)) > 1
);

সুতরাং, জাঙ্গো ওআরএম ব্যবহার করে এটি নির্বাচন করা কি সম্ভব? বা আরও ভাল এসকিউএল সমাধান?

উত্তর:


199

চেষ্টা করুন:

from django.db.models import Count
Literal.objects.values('name')
               .annotate(Count('id')) 
               .order_by()
               .filter(id__count__gt=1)

এটি জ্যাঙ্গোর সাথে আপনি যতটা পেতে পারেন তত কাছাকাছি। সমস্যাটি হ'ল এটি ValuesQuerySetকেবল nameএবং সাথে একটি ফিরে আসবে count। যাইহোক, আপনি QuerySetএটির পরে আবার কোনও ক্যোয়ারিতে ফিড করে নিয়মিত বানানোর জন্য এটি ব্যবহার করতে পারেন :

dupes = Literal.objects.values('name')
                       .annotate(Count('id'))
                       .order_by()
                       .filter(id__count__gt=1)
Literal.objects.filter(name__in=[item['name'] for item in dupes])

5
সম্ভবত আপনি বোঝাতে চেয়েছেন Literal.objects.values('name').annotate(name_count=Count('name')).filter(name_count__gt=1)?
ড্রাগগোয়ন

আসল কোয়েরি দেয়Cannot resolve keyword 'id_count' into field
ড্রাগন

4
আপডেট হওয়া উত্তরের জন্য ধন্যবাদ, আমি মনে করি আমি এই সমাধানটির সাথে লেগে থাকব, আপনি এমনকি এটি ব্যবহার করে তালিকা বোধগম্যতা ছাড়াই এটি করতে পারেনvalues_list('name', flat=True)
ড্রাগগোওন

4
জাজানো এর আগে একটি বাগ ছিল (সাম্প্রতিক সংস্করণগুলিতে সংশোধন করা হতে পারে) যেখানে আপনি যদি Countটীকা হিসাবে সংরক্ষণের জন্য কোনও ক্ষেত্রের নাম নির্দিষ্ট না করেন তবে এটি ডিফল্ট হয় [field]__count। যাইহোক, এই ডাবল-আন্ডারস্কোর সিনট্যাক্সটি হ'ল জ্যাঙ্গো আপনাকে কীভাবে যোগদান করতে চাইলে তা ব্যাখ্যা করে। সুতরাং, মূলত আপনি যখন এটিতে ফিল্টার করার চেষ্টা করবেন, জাজাঙ্গো মনে করেন আপনি এমন একটি সংযোগ করার চেষ্টা করছেন countযা স্পষ্টতই বিদ্যমান নেই। এই ফিক্সটি হ'ল আপনার এনটোটেশন ফলাফলের জন্য একটি নাম নির্দিষ্ট করা, অর্থাত্ annotate(mycount=Count('id'))তার mycountপরিবর্তে ফিল্টার করুন ।
ক্রিস প্র্যাট

4
যদি আপনি values('name')আপনার কলটি টীকা টানানোর পরে আর একটি কল যুক্ত করেন , আপনি তালিকাটি বোঝার অপসারণ করতে পারেন এবং বলতে পারেন Literal.objects.filter(name__in=dupes)যা এটিকে সমস্ত একক ক্যোয়ারিতে সম্পাদন করার অনুমতি দেবে।
পাইপার মেরিয়ামিয়াম

45

এটি সম্পাদনা হিসাবে প্রত্যাখ্যান করা হয়েছিল। সুতরাং এখানে এটি একটি ভাল উত্তর হিসাবে

dups = (
    Literal.objects.values('name')
    .annotate(count=Count('id'))
    .values('name')
    .order_by()
    .filter(count__gt=1)
)

এটি ValuesQuerySetসমস্ত সদৃশ নামের সাথে একটি ফিরিয়ে দেবে । যাইহোক, আপনি QuerySetএটির পরে আবার কোনও ক্যোয়ারিতে ফিড করে নিয়মিত তৈরি করতে এটি ব্যবহার করতে পারেন । জ্যাঙ্গো ওআরএম এগুলি একক ক্যোয়ারিতে একত্রিত করার জন্য যথেষ্ট স্মার্ট:

Literal.objects.filter(name__in=dups)

.values('name')টীকা কলের পরে অতিরিক্ত কলটি কিছুটা অদ্ভুত দেখাচ্ছে। এটি ছাড়া সাবকোয়ারি ব্যর্থ হয়। অতিরিক্ত মানগুলি ওআরএমকে কেবল সাবকোয়ারির জন্য নাম কলামটি নির্বাচন করার কৌশল দেয়।


সুন্দর কৌশল, দুর্ভাগ্যক্রমে এটি কেবল তখনই কাজ করবে যদি কেবলমাত্র একটি মান ব্যবহৃত হয় (যেমন, 'নাম' এবং 'ফোন' যেখানে ব্যবহৃত হয়, শেষ অংশটি কাজ করবে না)।
গ্যাভাল

4
কিসের .order_by()জন্য?
স্টিফানফুলিস

4
@ স্টেফানফৌলিস এটি বিদ্যমান বিদ্যমান অর্ডারকে সাফ করে দেয়। আপনার যদি কোনও মডেল-সেট অর্ডারিং থাকে তবে এটি এসকিউএল GROUP BYক্লজের অংশ হয়ে যায় এবং এটি জিনিসগুলি ভেঙে দেয়। সাবকিউরির সাথে খেলার সময় এটি খুঁজে পেয়েছে (যার মাধ্যমে আপনি খুব অনুরূপ গ্রুপিং করেন .values())
অলি

10

একত্রিতকরণ ব্যবহার করার চেষ্টা করুন

Literal.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1)

ঠিক আছে, এটি নামের তালিকার তালিকা দেয় তবে একই সাথে এইডস এবং অন্যান্য ক্ষেত্রগুলি নির্বাচন করা কি সম্ভব?
ড্রাগগোআন

@ ডিগ্রাওন - ক্রিস প্রট তার উত্তরে বিকল্পটি কভার করেছেন।
জেমসও 24'12

5

আপনি যদি পোস্টগ্রিজ এসকিউএল ব্যবহার করেন তবে আপনি এর মতো কিছু করতে পারেন:

from django.contrib.postgres.aggregates import ArrayAgg
from django.db.models import Func, Value

duplicate_ids = (Literal.objects.values('name')
                 .annotate(ids=ArrayAgg('id'))
                 .annotate(c=Func('ids', Value(1), function='array_length'))
                 .filter(c__gt=1)
                 .annotate(ids=Func('ids', function='unnest'))
                 .values_list('ids', flat=True))

এটি বরং এই সাধারণ এসকিউএল ক্যোয়ারিতে ফলাফল দেয়:

SELECT unnest(ARRAY_AGG("app_literal"."id")) AS "ids"
FROM "app_literal"
GROUP BY "app_literal"."name"
HAVING array_length(ARRAY_AGG("app_literal"."id"), 1) > 1

0

আপনি যদি কেবলমাত্র নামের তালিকা তৈরি করতে চান তবে অবজেক্টগুলি না, আপনি নিম্নলিখিত কোয়েরিটি ব্যবহার করতে পারেন

repeated_names = Literal.objects.values('name').annotate(Count('id')).order_by().filter(id__count__gt=1).values_list('name', flat='true')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.