জ্যাঙ্গোর কোনও ক্যুরিসেট থেকে প্রথম অবজেক্টটি পাওয়ার দ্রুততম উপায়?


193

জ্যাঙ্গোর ক্যোয়ারীসেট থেকে প্রায়শই আমি নিজেকে প্রথম অবজেক্টটি পেতে চাই, বা Noneযদি কিছু না থাকে তবে ফিরে আসতে চাই । এটি করার অনেক উপায় রয়েছে যা সমস্ত কাজ করে। তবে আমি ভাবছি সবচেয়ে পারফরম্যান্ট কোনটি।

qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
    return qs[0]
else:
    return None

এর ফলে দুটি ডাটাবেস কল আসে? এটা অপব্যয় বলে মনে হচ্ছে। এটি কোন দ্রুত?

qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
    return qs[0]
else:
    return None

অন্য বিকল্পটি হ'ল:

qs = MyModel.objects.filter(blah = blah)
try:
    return qs[0]
except IndexError:
    return None

এটি একটি একক ডাটাবেস কল উত্পন্ন করে, যা ভাল। তবে একটি ব্যতিক্রমী অবজেক্ট তৈরি করতে প্রচুর সময় প্রয়োজন, যা যখন আপনার সত্যিকারের প্রয়োজন হয় তা-ও-পরীক্ষা যদি খুব প্রয়োজন হয় তখন এটি করা খুব স্মৃতি-নিবিড় বিষয়।

আমি কীভাবে এটি কেবলমাত্র একটি একক ডাটাবেস কল এবং ব্যতিক্রম অবজেক্টের সাথে মেমরি মন্থন না করে করতে পারি?


21
থাম্বের বিধি: আপনি যদি ডিবি রাউন্ড-ট্রিপগুলি হ্রাস করার বিষয়ে উদ্বিগ্ন len()হন, সন্ধানের ক্ষেত্রে ব্যবহার করবেন না , সর্বদা ব্যবহার করুন .count()
ড্যানিয়েল ডিপোলো

7
"অনেক সময় একটি ব্যতিক্রম বস্তু তৈরি করা, যা একটি খুব স্মৃতি-নিবিড় বিষয়" - যদি আপনি একটি অতিরিক্ত ব্যতিক্রম তৈরি করার বিষয়ে উদ্বিগ্ন হন তবে আপনি পাইথনটি পুরো জায়গাতে ব্যতিক্রম ব্যবহার করার কারণে এটি ভুল করছেন। আপনি কি সত্যই বেঞ্চমার্ক করেছেন যে এটি আপনার ক্ষেত্রে স্মৃতি-নিবিড়?
lqc

1
@ লিপড এবং যদি আপনি আসলে কোনওভাবেই এঞ্জারটিকে বেঞ্চমার্ক করেন (অথবা কমপক্ষে মন্তব্যগুলি), আপনি জানতেন যে এটি কোনও দ্রুত নয়। এটি আসলে ধীর হতে পারে, 'আপনার অতিরিক্ত তালিকা তৈরি করার কারণ এটি এড়িয়ে যেতে পারে। অজগর ফাংশন কল করার জন্য বা জ্যাঙ্গোর ওআরএম প্রথমে ব্যবহারের ব্যয়ের তুলনায় যা কেবলমাত্র চিনাবাদাম! ফিল্টার করার জন্য একটি একক কল অনেকগুলি, অনেকগুলি ধীরে ধীরে তারপরে একটি ব্যতিক্রম উত্থাপন করে (যা এখনও উত্থাপণযোগ্য, 'কারণ এটি পুনরায় প্রোটোকল কীভাবে কাজ করে!)।
lqc

1
আপনার স্বজ্ঞাততাটি সঠিক যে পারফরম্যান্সের পার্থক্যটি ছোট, তবে আপনার উপসংহারটি ভুল। আমি একটি বেঞ্চমার্ক চালিয়েছি এবং গ্রহণযোগ্য উত্তর সত্যিকারের ব্যবধানে দ্রুততর হয়। চিত্রে যান.
লিওপড

11
জনগণ জ্যাঙ্গো ১. using ব্যবহার করে, অবশেষে তারা সুবিধার্থে first()এবং last()সুবিধাদির পদ্ধতিগুলি যুক্ত করেছেন: ডকস.ডজ্যাঙ্গোপ্রজেক্ট
ওয়ে ইয়েন

উত্তর:


328

জ্যাঙ্গো 1.6 (নভেম্বর 2013 প্রকাশিত) সুবিধার পদ্ধতিগুলি চালু করেছে first()এবং last()যা ফলাফল ব্যতিক্রমগুলি গ্রাস করে এবং Noneযদি ক্যোরিসেট কোনও বস্তু না ফেরায় তবে ফিরে আসে।


1
এটি [: 1] করে না, সুতরাং এটি তত দ্রুত নয় (যদি না আপনি যেভাবে পুরো ক্যোরিসেটটি মূল্যায়নের প্রয়োজন হয়)।
janek37

13
এছাড়াও, first()এবং কোনও প্রশ্নের উপর একটি ধারা last()প্রয়োগ ORDER BYকরুন। এটি ফলাফলগুলি নির্বিচারে তৈরি করবে তবে সম্ভবত ক্যোয়ারীটি ধীর করবে।
ফিল ক্রেলভ

@ জানেক 37- এর পারফরম্যান্সে কোনও পার্থক্য নেই Cod3monk3y দ্বারা নির্দেশিত হিসাবে, এটি একটি সুবিধাজনক পদ্ধতি এবং এটি সম্পূর্ণ ক্যোরিসেটটি পড়েনি।
জোম্পপা

142

সঠিক উত্তরটি হ'ল

Entry.objects.all()[:1].get()

যা ব্যবহার করা যেতে পারে:

Entry.objects.filter()[:1].get()

আপনি প্রথমে এটিকে তালিকায় পরিণত করতে চান না কারণ এটি সমস্ত রেকর্ডের একটি সম্পূর্ণ ডাটাবেস কলকে বাধ্য করবে। কেবল উপরেরটি করুন এবং এটি কেবল প্রথমটি টানবে। এমনকি .order_byআপনি যেটি চান তা প্রথম পেতে নিশ্চিত করতে আপনি ব্যবহার করতে পারেন could

যোগ করার বিষয়টি নিশ্চিত করুন .get()বা অন্যথায় আপনি একটি ক্যোরিসেট ফিরে পাবেন এবং কোনও বস্তু নয়।


9
আপনার এখনও এটি চেষ্টা করে মোড়ানো প্রয়োজন ... অবজেক্টডোজনটেক্সিস্ট বাদে যা মূল তৃতীয় বিকল্পের মতো তবে কাটা কাটা দিয়ে।
ড্যানি ডব্লিউ। আদায়র

1
আপনি যদি শেষ পর্যন্ত কল পেতে () করতে চান তবে একটি লিমিটেড সেট করার কী দরকার? ওআরএম এবং এসকিউএল সংকলকটিকে তার ব্যাকএন্ডের জন্য সর্বোত্তম কী তা সিদ্ধান্ত নিতে দিন (উদাহরণস্বরূপ, ওরাকল জ্যাঙ্গোতে সীমাবদ্ধভাবে সীমাবদ্ধ করা হয়েছে, সুতরাং এটি সাহায্যের পরিবর্তে আঘাত করবে)।
lqc

আমি এই উত্তরটি পেছনের .get () ছাড়াই ব্যবহার করেছি। যদি কোনও তালিকা ফিরে আসে তবে আমি তালিকার প্রথম উপাদানটি ফিরিয়ে দেব।
কিথ জন হাচিসন

থাকার আলাদা কি Entry.objects.all()[0]??
জেমস লিন

15
@ জেমসলিন পার্থক্যটি হ'ল [: 1] .get () DoNotExist উত্থাপন করে, [[]] সূচিপত্র উত্থাপন করে।
রোপেজ

49
r = list(qs[:1])
if r:
  return r[0]
return None

1
আপনি যদি ট্রেসিং চালু করেন তবে আমি নিশ্চিত যে আপনি এটিকে LIMIT 1ক্যোয়ারীতে যুক্ত করে দেখবেন এবং আমি জানি না যে আপনি এর চেয়ে আরও ভাল কিছু করতে পারেন। যাইহোক, অভ্যন্তরীণভাবে __nonzero__মধ্যে QuerySetহিসাবে প্রয়োগ করা হয় try: iter(self).next() except StopIteration: return false..., তাই এটি ব্যতিক্রম অব্যাহতি না।
বেন জ্যাকসন

@ বেন: সত্যতা যাচাইয়ের আগে কোনওটিকে রূপান্তরিত QuerySet.__nonzero__()হওয়ার পরে কখনও বলা হয় না । অন্যান্য ব্যতিক্রমগুলি এখনও ঘটতে পারে। QuerySetlist
ইগনাসিও ওয়াজকেজ-আব্রামস

@ অ্যারন: এটি একটি StopIterationব্যতিক্রম উত্পন্ন করতে পারে ।
Ignacio Vazquez-Abram

তালিকায় রূপান্তর === __iter__একটি নতুন পুনরাবৃত্তকারী অবজেক্ট পেতে কল করুন এবং নিক্ষেপ nextনা হওয়া অবধি এর পদ্ধতিটিতে কল করুন StopIteration। তাই
স্পষ্টতই

14
এই উত্তরটি এখন পুরানো, জ্যাঙ্গো 1.6+ এর জন্য @ cod3monk3y জবাবটি দেখুন
ভ্যালায়াল

37

এখন, first() জাজানো ১.৯-এ আপনার ক্যোয়ারসেটের পদ্ধতি রয়েছে।

YourModel.objects.all().first()

এটির চেয়ে ভাল উপায় .get()বা [0]কারণ ক্যোরিসেটটি খালি থাকলে থেরোফরান, যদি এটি ব্যতিক্রম করে না তবে এটি ব্যবহার করে আপনাকে পরীক্ষা করতে হবে নাexists()


1
এটি এসকিউএল-তে একটি লিমিটেড 1 ঘটায় এবং আমি দাবি দেখেছি যে এটি ক্যোয়ারীটিকে আরও ধীর করে তুলতে পারে - যদিও আমি তা প্রমাণিত দেখতে চাই: যদি ক্যোয়ারীটি কেবলমাত্র একটি আইটেম ফেরত দেয়, তবে সত্যিই কেন LIMIT 1 কার্য সম্পাদনকে প্রভাবিত করবে? সুতরাং আমি মনে করি উপরের উত্তরটি ঠিক আছে, তবে নিশ্চিত প্রমাণগুলি দেখতে পছন্দ করবে।
rrauenza

আমি "আরও ভাল" বলব না। এটি সত্যই আপনার প্রত্যাশার উপর নির্ভর করে।
15

7

আপনি যদি প্রথম উপাদানটি প্রায়শই পাওয়ার পরিকল্পনা করেন - আপনি এই দিকে ক্যোরিসেটটি প্রসারিত করতে পারেন:

class FirstQuerySet(models.query.QuerySet):
    def first(self):
        return self[0]


class ManagerWithFirstQuery(models.Manager):
    def get_query_set(self):
        return FirstQuerySet(self.model)

এর মতো মডেলটি সংজ্ঞায়িত করুন:

class MyModel(models.Model):
    objects = ManagerWithFirstQuery()

এবং এটি এর মতো ব্যবহার করুন:

 first_object = MyModel.objects.filter(x=100).first()

অবজেক্টসকে কল করুন = ম্যানেজার উইথফার্সফ্যুয়ারি কে অবজেক্টস হিসাবে = ম্যানেজার উইথফার্সফ্যাকিউরি () - প্যারেন্টসগুলি ভুলে যাবেন না - যাইহোক, আপনি আমাকে এত সাহায্য করেছেন +1
কামিল

7

এটি পাশাপাশি কাজ করতে পারে:

def get_first_element(MyModel):
    my_query = MyModel.objects.all()
    return my_query[:1]

যদি এটি খালি থাকে, তবে একটি খালি তালিকা দেয়, অন্যথায় এটি তালিকার ভিতরে প্রথম উপাদানটি দেয়।


1
এটি এখন পর্যন্ত সেরা সমাধান ... ডাটাবেসে কেবল একটি কলের ফলাফল
Shh


3

আপনার বিদ্যমান জঞ্জো পদ্ধতি ব্যবহার করা উচিত। এটি আপনার ব্যবহারের জন্য এটি সেখানে।

if qs.exists():
    return qs[0]
return None

1
বাদে, যদি আমি এটি সঠিকভাবে বুঝতে পারি, আইডিয়োমেটিক পাইথন সাধারণত আপনি লাফ দেওয়ার আগে নজর না দেওয়ার চেয়ে অনুমতি ( ইএএফপি ) চেয়ে ক্ষমা চাওয়ার জন্য সহজতর ব্যবহার করেন ।
বিগস্মোকে

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

2

যেহেতু জাজানো ১.6 আপনি প্রথম () পদ্ধতিতে ফিল্টার () ব্যবহার করতে পারেন:

Model.objects.filter(field_name=some_param).first()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.