জ্যাঙ্গো ফিল্টার বনাম একক বস্তুর জন্য?


147

কিছু সহকর্মীর সাথে এ নিয়ে আমার বিতর্ক ছিল। জ্যাঙ্গোতে যখন আপনি কেবল একটির প্রত্যাশা করছেন তখন কোনও জিনিস পুনরুদ্ধার করার জন্য কি কোনও পছন্দনীয় উপায় আছে?

দুটি সুস্পষ্ট উপায় হ'ল:

try:
    obj = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
    # We have no object! Do something...
    pass

এবং:

objs = MyModel.objects.filter(id=1)

if len(objs) == 1:
    obj = objs[0]
else:
    # We have no object! Do something...
    pass

প্রথম পদ্ধতিটি আচরণগতভাবে আরও সঠিক বলে মনে হচ্ছে তবে নিয়ন্ত্রণ প্রবাহে ব্যতিক্রমগুলি ব্যবহার করে যা কিছু ওভারহেডের পরিচয় দিতে পারে। দ্বিতীয়টি আরও গোলাকার তবে কখনও ব্যতিক্রম বাড়াবে না।

এগুলির মধ্যে কোনটিই ভাল? কোনটি আরও দক্ষ?

উত্তর:


177

get()এই ক্ষেত্রে জন্য বিশেষভাবে সরবরাহ করা হয় । এটা ব্যবহার করো.

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


সবকিছু ঠিক আছে তবে উত্তর দেওয়ার জন্য আরও তথ্য যুক্ত করা উচিত? 1. পাইথন চেষ্টা / বাদ ( ইএএফপি দেখুন ) উত্সাহ দেয় , এজন্যই QS.get()ভাল। ২. বিশদ বিষয়: "কেবলমাত্র একটির প্রত্যাশা করা" এর অর্থ কি সর্বদা 0-1 টি অবজেক্ট থাকে, বা 2+ অবজেক্ট থাকা সম্ভব এবং সেই ক্ষেত্রেও এটি পরিচালনা করা উচিত (এই ক্ষেত্রে len(objs)একটি ভয়ঙ্কর ধারণা)? ৩. বেঞ্চমার্ক ব্যতীত ওভারহেড সম্পর্কে কিছু অনুমান করবেন না (আমি মনে করি যে এই ক্ষেত্রে try/exceptকমপক্ষে অর্ধেক কল ফিরে আসবে যতক্ষণ তত দ্রুততর হবে)
চাপিয়ে দেওয়া হয়েছে

> নামটি এমনকি এটি লেখা এবং প্রোফাইল তৈরির আগে কোডটি অপ্টিমাইজ করার চেষ্টা করা এটি একটি আকর্ষণীয় মন্তব্য। আমি সবসময় ভেবেছিলাম যে কোনও কিছু প্রয়োগের আগে আমার সবচেয়ে কার্যকর বিকল্প সম্পর্কে চিন্তা করা উচিত। এটা কি ভুল? আপনি কি এই বিষয়টিতে বিস্তারিত বলতে পারেন? এমন কিছু সংস্থান আছে যা এটিকে বিস্তারিতভাবে ব্যাখ্যা করে?
পার্থ শর্মা

আমি অবাক হয়েছি কেউ প্রথমে () উল্লেখ করেনি। অন্যান্য পরামর্শগুলি মনে হচ্ছে এটি এই দৃশ্যের জন্য করা কল। stackoverflow.com/questions/5123839/...
NeilG

29

আপনি জ্যাঙ্গো-বিরক্তিকর নামে একটি মডিউল ইনস্টল করতে পারেন এবং তারপরে এটি করুন:

from annoying.functions import get_object_or_None

obj = get_object_or_None(MyModel, id=1)

if not obj:
    #omg the object was not found do some error stuff

1
কেন এ জাতীয় পদ্ধতি ব্যবহার করা বিরক্তিকর? আমার ভাল লাগছে!
টমাস

17

1 সঠিক। পাইথনে একটি ব্যতিক্রমের ফিরতে সমান ওভারহেড থাকে। একটি সরলীকৃত প্রমাণ জন্য আপনি তাকান করতে পারেন এই

2 জ্যাঙ্গো ব্যাকএন্ডে এটি করছে। কোনও আইটেম পাওয়া না গেলে বা একাধিক বস্তুর সন্ধান পেলে getকল করে filterএবং একটি ব্যতিক্রম উত্থাপন করে।


1
সেই পরীক্ষাটি বেশ অন্যায়। একটি ব্যতিক্রম ছোঁড়াতে ওভারহেডের একটি বড় অংশ হ'ল স্ট্যাক ট্রেস হ্যান্ডলিং। এই পরীক্ষার একটি স্ট্যাকের দৈর্ঘ্য ছিল 1 যা আপনি সাধারণত কোনও অ্যাপ্লিকেশনটিতে পাবেন তার চেয়ে অনেক কম।
রব ইয়ং

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

12

আমি পার্টিতে কিছুটা দেরি করেছি, তবে জাজানো ১.6 এর সাথে রয়েছে first() জাঙ্গো ১. 1. এর সাথে ক্যোয়ারসেটে পদ্ধতি রয়েছে।

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


ক্যোরিসেটের সাথে ম্যাচ করা প্রথম অবজেক্টটি বা কোনও মিল নেই এমন বস্তুটি ফেরত দেয়। যদি ক্যোরিসেটের কোনও অর্ডিং সংজ্ঞায়িত না হয়, তবে প্রাথমিক কী দ্বারা ক্যোরিসেটটি স্বয়ংক্রিয়ভাবে অর্ডার হয়ে গেছে।

উদাহরণ:

p = Article.objects.order_by('title', 'pub_date').first()
Note that first() is a convenience method, the following code sample is equivalent to the above example:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None

এটি গ্যারান্টি দেয় না যে আপনার কাছে ক্যোয়ারিতে কেবলমাত্র একটি অবজেক্ট রয়েছে
py_dude

8

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

এছাড়াও (আবার, অনুমান) দ্বিতীয় বিকল্পটি কোনও ধরণের ফলাফল সংগ্রহ বা পুনরুক্তিযোগ্য বস্তু তৈরি করতে পারে যেহেতু ফিল্টার () কলটি সাধারণত অনেকগুলি সারি ফেরত দিতে পারে। আপনি এটিকে () দিয়ে বাইপাস করুন d

শেষ অবধি, প্রথম বিকল্পটি উভয়ই খাটো এবং অতিরিক্ত অস্থায়ী পরিবর্তনশীল বাদ দেয় - কেবলমাত্র একটি সামান্য পার্থক্য তবে প্রতিটি সামান্য সাহায্য করে।


জ্যাঙ্গোর সাথে কোনও অভিজ্ঞতা নেই তবে এখনও স্পট করে। ডিফল্টরূপে সুস্পষ্ট, সংশ্লেষ এবং সুরক্ষিত হওয়া ভাষা বা কাঠামো নির্বিশেষে ভাল নীতিগুলি।
নেভেলিস

8

কেন যে সমস্ত কাজ? 1 বিল্টিন শর্টকাট দিয়ে 4 টি লাইন প্রতিস্থাপন করুন। (এটি নিজস্ব চেষ্টা করে / বাদে করে))

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)

1
এটি দুর্দান্ত যখন এটি পছন্দসই আচরণ হয় তবে কখনও কখনও আপনি অনুপস্থিত বস্তুটি তৈরি করতে চাইতে পারেন বা টানটি optionচ্ছিক তথ্য ছিল।
সিঙ্গেলাইজেশন ইলিমিনেশন

2
এটা কী Model.objects.get_or_create()জন্য
boatcoder

7

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

তবে এটি জ্যাঙ্গোর ওআরএম, এবং সম্ভবত ডাটাবেসের রাউন্ড-ট্রিপ, বা এমনকি কোনও ক্যাশেড ফলাফলগুলি পারফরম্যান্সের বৈশিষ্ট্যগুলিকে প্রাধান্য দিতে পারে, তাই আপনি পঠনযোগ্যতার পক্ষে থাকবেন, যেহেতু আপনি ঠিক এক ফলাফল আশা করেন, ব্যবহার করুন get()


4

আমি এই সমস্যাটিটি কিছুটা খেলেছি এবং আবিষ্কার করেছি যে বিকল্পটি 2 দুটি এসকিউএল কোয়েরি কার্যকর করে, যা এতো সাধারণ কাজের জন্য অতিরিক্ত। আমার টিকা দেখুন:

objs = MyModel.objects.filter(id=1) # This does not execute any SQL
if len(objs) == 1: # This executes SELECT COUNT(*) FROM XXX WHERE filter
    obj = objs[0]  # This executes SELECT x, y, z, .. FROM XXX WHERE filter
else: 
    # we have no object!  do something
    pass

একটি সমমানের সংস্করণ যা একটি একক ক্যোয়ারিকে চালিত করে:

items = [item for item in MyModel.objects.filter(id=1)] # executes SELECT x, y, z FROM XXX WHERE filter
count = len(items) # Does not execute any query, items is a standard list.
if count == 0:
   return None
return items[0]

এই পদ্ধতির দিকে স্যুইচ করে, আমি আমার অ্যাপ্লিকেশন সম্পাদন করে এমন প্রশ্নের সংখ্যা যথেষ্ট পরিমাণে হ্রাস করতে সক্ষম হয়েছি।


1

আকর্ষণীয় প্রশ্ন, তবে আমার জন্য অকাল অপ্টিমাইজেশনের # 2 টি বিকল্প রয়েছে। আমি নিশ্চিত না যে কোনটি আরও পারফরম্যান্ট, তবে বিকল্প # 1 অবশ্যই আমার কাছে আরও পাইথোনিক দেখায় এবং অনুভব করে।


1

আমি একটি ভিন্ন নকশা পরামর্শ।

আপনি যদি কোনও সম্ভাব্য ফলাফলের জন্য কোনও ক্রিয়াকলাপ সম্পাদনা করতে চান তবে আপনি কোয়েরীসেট থেকে উত্স পেতে পারেন: http://djangosnippets.org/snippets/734/

ফলাফলটি বেশ দুর্দান্ত, উদাহরণস্বরূপ:

MyModel.objects.filter(id=1).yourFunction()

এখানে, ফিল্টারটি খালি ক্যুয়ারেট বা একটি আইটেমের সাথে ক্যোরিসেট দেয় set আপনার কাস্টম ক্যোয়ারসেট ফাংশনগুলি চেইনযোগ্য এবং পুনরায় ব্যবহারযোগ্য। আপনি আপনার সমস্ত এন্ট্রি জন্য তা আদায় করতে চাইলে: MyModel.objects.all().yourFunction()

এডমিন ইন্টারফেসে ক্রিয়া হিসাবে ব্যবহার করার জন্য এগুলি আদর্শ:

def yourAction(self, request, queryset):
    queryset.yourFunction()

0

বিকল্প 1 আরও মার্জিত, তবে চেষ্টা করুন ... বাদে অবশ্যই ব্যবহার করুন।

আমার নিজের অভিজ্ঞতা থেকে আমি আপনাকে বলতে পারি যে মাঝে মাঝে আপনি নিশ্চিত হয়ে থাকেন যে সম্ভবত ডাটাবেসে একের বেশি মেলানো অবজেক্ট থাকতে পারে না, এবং তবুও দুটি থাকবে ... (অবশ্যই তার প্রাথমিক কী দ্বারা অবজেক্টটি পাওয়ার পরে)।


0

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

যদি ব্যবহারকারী আইডিটি অনুসন্ধান করে তবে আমি চালাতে পারি:

Record.objects.get(pk=id)

যা জাঙ্গোর প্যাগিনেটরে ত্রুটি ফেলে দেয় কারণ এটি একটি রেকর্ড এবং রেকর্ডসের ক্যোরিসেট নয়।

আমার চালানো দরকার:

Record.objects.filter(pk=id)

যা এতে একটি আইটেম দিয়ে একটি ক্যোরিসেট প্রদান করে। তারপরে প্যাগেইনেটর ঠিক ঠিক কাজ করে।


প্যাগিনেটার - বা কোনও কার্যকারিতা যা কোয়েরীসেটের প্রত্যাশা করে - ব্যবহার করার জন্য আপনার প্রশ্নের অবশ্যই একটি ক্যোয়ারীসেট ফেরত যেতে হবে। .Filter () এবং .get () ব্যবহার করে .filter () দিয়ে স্টিক করবেন না এবং "pk = id" ফিল্টার সরবরাহ করবেন না, যেমনটি আপনি ইতিমধ্যে বুঝতে পেরেছেন। এই ব্যবহারের ক্ষেত্রে এটিই প্যাটার্ন।
কর্নেল ম্যাসন

0

.পাওয়া()

প্রদত্ত লুকোচুরি পরামিতিগুলির সাথে মিলে যাওয়া বস্তুটি ফেরত দেয়, যা ফিল্ড লুকআপগুলিতে বর্ণিত বিন্যাসে হওয়া উচিত।

get () একাধিক বস্তুর সন্ধান পেলে মাল্টিপলঅবজেক্টস রিটার্ন করা হয়। মাল্টিপলঅবজেক্টস রিটার্নার্ড ব্যতিক্রম মডেল শ্রেণির একটি বৈশিষ্ট্য।

get () প্রদত্ত প্যারামিটারগুলির জন্য যদি কোনও বস্তু খুঁজে পাওয়া যায় না, তবে একটি doNotExist ব্যতিক্রম উত্থাপন করে। এই ব্যতিক্রমটি মডেল শ্রেণির একটি বৈশিষ্ট্যও।

.ছাঁকনি()

প্রদত্ত লুকিং প্যারামিটারগুলির সাথে মেলে এমন একটি নতুন কোয়েরি সেট দেয় objects

বিঃদ্রঃ

আপনি যখন কোনও একক অনন্য বস্তু পেতে চান তখন (এবং) ফিল্টার () ব্যবহার করুন যখন আপনি আপনার অনুসন্ধান পরামিতিগুলির সাথে মেলে এমন সমস্ত বস্তু পেতে চান।

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