संपत्ति द्वारा फ़िल्टर करें


95

क्या मॉडल संपत्ति के आधार पर Django क्वेरी को फ़िल्टर करना संभव है?

मेरे मॉडल में एक विधि है:

@property
def myproperty(self):
    [..]

और अब मैं इस संपत्ति को फ़िल्टर करना चाहता हूं जैसे:

MyModel.objects.filter(myproperty=[..])

क्या यह किसी तरह संभव है?


यह SQLAlchemy में है: docs.sqlalchemy.org/en/latest/orm/extensions/hybrid.html और आप django को SQLAlchemy से pypi.pythy.org/pypi/aldjemy के माध्यम से जोड़ सकते हैं लेकिन मुझे संदेह है कि दोनों को कनेक्ट किया जा सकता है जिस तरह से आप उन्हें चाहते हैं।
Rattray

जवाबों:


78

नहीं। Django फ़िल्टर SQL स्तर पर डेटाबेस स्तर पर काम करते हैं। पायथन गुणों के आधार पर फ़िल्टर करने के लिए, आपको संपत्ति का मूल्यांकन करने के लिए ऑब्जेक्ट को पायथन में लोड करना होगा - और उस बिंदु पर, आप इसे लोड करने के लिए सभी काम पहले ही कर चुके हैं।


4
दुर्भाग्य यह है कि इस सुविधा को लागू नहीं किया गया है, परिणामी निर्माण के बाद कम से कम मिलान वाली वस्तुओं को फ़िल्टर करने के लिए एक दिलचस्प विस्तार होगा ।
श्नाइक

1
प्रशासन में इससे कैसे निपटें? क्या कुछ वर्कअराउंड है?
औरिलाब

39

मैं आपके मूल प्रश्न को गलत समझ सकता हूं, लेकिन अजगर में एक फिल्टर बिलिन है।

filtered = filter(myproperty, MyModel.objects)

लेकिन सूची समझ का उपयोग करना बेहतर है :

filtered = [x for x in MyModel.objects if x.myproperty()]

या इससे भी बेहतर, एक जनरेटर अभिव्यक्ति :

filtered = (x for x in MyModel.objects if x.myproperty())

14
एक बार जब आपके पास पायथन ऑब्जेक्ट होता है, तो इसे फ़िल्टर करने का काम करता है, लेकिन वह Django QuerySet.filter के बारे में पूछ रहा है, जो SQL प्रश्नों का निर्माण करता है।
ग्लेन मेनार्ड

1
सही है, लेकिन जैसा कि ऊपर बताया गया है, मैं संपत्ति को अपने डेटाबेस फ़िल्टर में जोड़ना चाहूंगा। क्वेरी किए जाने के बाद फ़िल्टर करना बिल्कुल वही है जिससे मैं बचना चाहता हूं।
श्नाइक

18

@ TheGrimmScientist के सुझाए गए वर्कअराउंड को रोकते हुए, आप इन "sql संपत्तियों" को प्रबंधक या QuerySet पर परिभाषित करके और पुनः उपयोग / श्रृंखला बना सकते हैं / बना सकते हैं:

एक प्रबंधक के साथ:

class CompanyManager(models.Manager):
    def with_chairs_needed(self):
        return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))

class Company(models.Model):
    # ...
    objects = CompanyManager()

Company.objects.with_chairs_needed().filter(chairs_needed__lt=4)

QuerySet के साथ:

class CompanyQuerySet(models.QuerySet):
    def many_employees(self, n=50):
        return self.filter(num_employees__gte=n)

    def needs_fewer_chairs_than(self, n=5):
        return self.with_chairs_needed().filter(chairs_needed__lt=n)

    def with_chairs_needed(self):
        return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))

class Company(models.Model):
    # ...
    objects = CompanyQuerySet.as_manager()

Company.objects.needs_fewer_chairs_than(4).many_employees()

अधिक के लिए https://docs.djangoproject.com/en/1.9/topics/db/managers/ देखें । ध्यान दें कि मैं दस्तावेज़ीकरण बंद कर रहा हूं और उपरोक्त का परीक्षण नहीं किया है।


14

लगता है कि एनोटेशन के साथ एफ () का उपयोग करना मेरे लिए इसका समाधान होगा।

यह फ़िल्टर करने वाला नहीं है @property, क्योंकि Fऑब्जेक्ट्स को अजगर में लाने से पहले डेटाबेस से बात की जाती है। लेकिन फिर भी इसे एक उत्तर के रूप में यहाँ रखा गया है क्योंकि संपत्ति द्वारा फ़िल्टर करने के लिए मेरे कारण वास्तव में दो अलग-अलग क्षेत्रों पर साधारण अंकगणित के परिणाम से वस्तुओं को फ़िल्टर करना चाहते थे।

तो, कुछ की तर्ज पर:

companies = Company.objects\
    .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
    .filter(chairs_needed__lt=4)

संपत्ति को परिभाषित करने के बजाय:

@property
def chairs_needed(self):
    return self.num_employees - self.num_chairs

फिर सभी वस्तुओं पर एक सूची की समझ बनाना।


4

मुझे भी यही समस्या थी, और मैंने इसका सरल समाधान विकसित किया:

objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)

मुझे पता है कि यह सबसे अधिक उपयोगी समाधान नहीं है, लेकिन खान के रूप में सरल मामलों में मदद कर सकता है


3

कृपया किसी ने मुझे सही किया, लेकिन मुझे लगता है कि मुझे एक समाधान मिल गया है, कम से कम अपने मामले के लिए।

मैं उन सभी तत्वों पर काम करना चाहता हूं जिनके गुण बिल्कुल समान हैं ... जो भी हो।

लेकिन मेरे पास कई मॉडल हैं, और इस दिनचर्या को सभी मॉडलों के लिए काम करना चाहिए। और यह करता है:

def selectByProperties(modelType, specify):
    clause = "SELECT * from %s" % modelType._meta.db_table

    if len(specify) > 0:
        clause += " WHERE "
        for field, eqvalue in specify.items():
            clause += "%s = '%s' AND " % (field, eqvalue)
        clause = clause [:-5]  # remove last AND

    print clause
    return modelType.objects.raw(clause)

इस सार्वभौमिक सबरूटीन के साथ, मैं उन सभी तत्वों का चयन कर सकता हूं जो मेरे 'निर्दिष्ट' (प्रॉपर्टी, प्रॉपर्टी) संयोजनों के बिल्कुल समान हैं।

पहला पैरामीटर (मॉडल। मॉडल),

दूसरा शब्द जैसे: {"संपत्ति 1": "77", "संपत्ति 2": "12"}

और यह एक SQL स्टेटमेंट बनाता है

SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'

और उन तत्वों पर एक QuerySet लौटाता है।

यह एक परीक्षण कार्य है:

from myApp.models import myModel

def testSelectByProperties ():

    specify = {"property1" : "77" , "property2" : "12"}
    subset = selectByProperties(myModel, specify)

    nameField = "property0"
    ## checking if that is what I expected:
    for i in subset:
        print i.__dict__[nameField], 
        for j in specify.keys():
             print i.__dict__[j], 
        print 

तथा? तुम क्या सोचते हो?


आम तौर पर यह एक सभ्य काम के आसपास लगता है। मैं यह नहीं कहूंगा कि यह आदर्श है, लेकिन यह हर बार जब आप इस तरह की जरूरत के लिए PyPI से स्थापित पैकेजों के लिए मॉडल को संशोधित करने के लिए एक भंडार भरने के लिए धड़कता है।
hlongmore

और अब है कि मैं समय इसके साथ एक सा खेलने के लिए मिला है: इस दृष्टिकोण के लिए असली नकारात्मक पक्ष यह है कि क्वेरीसमूहों .raw () द्वारा दिया है पूर्ण विकसित क्वेरीसमूहों, जिसके द्वारा मेरा मतलब है वहाँ क्वेरीसमूह तरीकों कि याद कर रहे हैं कर रहे हैं नहीं कर रहे हैं:AttributeError: 'RawQuerySet' object has no attribute 'values'
hlongmore

1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन यहां कूदने वालों के लिए मुझे लगता है कि नीचे दिए गए सवाल और रिश्तेदार को पढ़ना उपयोगी है:

Django 1.4 में व्यवस्थापक फ़िल्टर को कैसे अनुकूलित करें


1
इस उत्तर को संक्षिप्त करने वालों के लिए - यह लिंक "सिम्पलिस्टलिस्ट" का उपयोग करके Django एडमिन में लिस्ट फ़िल्टर्स को लागू करने के बारे में जानकारी के लिए है। बहुत विशिष्ट मामले को छोड़कर उपयोगी, लेकिन सवाल का जवाब नहीं।
21

0

यह भी संभव हो सकता है कि क्वेरी एनोटेशन का उपयोग करें जो संपत्ति को डुप्लिकेट / सेट-लॉजिक के रूप में करते हैं, जैसा कि @rattray और @thegrimmscientist द्वारा सुझाया गया है , के साथ संयोजन के रूप में property। यह कुछ ऐसा परिणाम दे सकता है जो पायथन स्तर और डेटाबेस स्तर पर दोनों पर काम करता है।

हालांकि, कमियों के बारे में निश्चित नहीं है: उदाहरण के लिए इस SO प्रश्न को देखें ।


आपका कोड समीक्षा प्रश्न लिंक एक सूचना देता है कि इसे स्वेच्छा से इसके लेखक ने हटा दिया था। क्या आप यहां अपना जवाब अपडेट करने का मन करेंगे, या तो कोड के लिंक के साथ, या स्पष्टीकरण के साथ, या बस अपना उत्तर हटा दें?
हंगलमोर

@ लोंगमोर: इसके लिए क्षमा करें। यह सवाल एसओ के पास ले जाया गया। मैंने ऊपर लिंक तय किया।
djvg
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.