2010-12-03 10 views
9

मैं कुछ डेटाबेस ऑब्जेक्ट्स को एक समेकित स्ट्रिंग द्वारा फ़िल्टर करना चाहता हूं।डीजेगो ओआरएम: अतिरिक्त विशेषता द्वारा फ़िल्टर

सामान्य SQL क्वेरी होगा:

SELECT concat(firstName, ' ', name) FROM person WHERE CONCAT(firstName, ' ', name) LIKE "a%"; 

मॉडल में, मैं बनाया है एक प्रबंधक PersonObjects कहा जाता है:

class PersonObjects(Manager): 
    attrs = { 
     'fullName': "CONCAT(firstName, ' ', name)" 
    } 

    def get_query_set(self): 
     return super(PersonObjects, self).get_query_set().extra(
      select=self.attrs) 

मैं भी अपने मॉडल में यह कॉन्फ़िगर किया:

objects = managers.PersonObjects() 

अब पूर्ण वस्तुओं तक पहुंच एकल वस्तुओं के लिए काम करता है:

>>> p = models.Person.objects.get(pk=4) 
>>> p.fullName 
u'Fred Borminski' 

लेकिन यह एक फिल्टर में काम नहीं करता:

>>> p = models.Person.objects.filter(fullName__startswith='Alexei') 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/usr/lib/python2.7/site-packages/django/db/models/manager.py", line 141, in filter 
    return self.get_query_set().filter(*args, **kwargs) 
    File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 550, in filter 
    return self._filter_or_exclude(False, *args, **kwargs) 
    File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 568, in _filter_or_exclude 
    clone.query.add_q(Q(*args, **kwargs)) 
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1128, in add_q 
    can_reuse=used_aliases) 
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1026, in add_filter 
    negate=negate, process_extras=process_extras) 
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1191, in setup_joins 
    "Choices are: %s" % (name, ", ".join(names))) 
FieldError: Cannot resolve keyword 'fullName' into field. Choices are: firstName, gender, name, (...) 

यह एक बग या एक विशेषता है? मैं इसे कैसे ठीक करूं?

धन्यवाद।

उत्तर

16

यह एक बग नहीं है। filter() केवल मॉडल परिभाषाओं का निरीक्षण करता है, इसलिए यह घोषित क्षेत्र के रूप में fullName को पहचान नहीं करता है (क्योंकि यह नहीं है - यह एक क्वेरी में एक अतिरिक्त तर्क है)।

Person.objects.extra(where=["fullName LIKE %s"], params=["Alexei%"]) 
+0

दुर्भाग्य से यह काम नहीं करता है। यह अभी भी पूर्णनाम विशेषता नहीं ढूंढने के बारे में शिकायत करता है। ऑब्जेक्ट से पूर्णनाम विशेषता को पुनर्प्राप्त करना हालांकि काम करता है। क्या यह 'अतिरिक्त' विधि किसी भी तरह से प्रबंधक से पहले सेट अतिरिक्त विशेषताओं को ओवरराइट करता है? –

+1

असल में यह या तो काम नहीं करता है: 'models.Person.objects.extra (select = {' fullName ': "CONCAT (firstName,' ', name)"}, जहां = [' fullName LIKE% s '], पैरा = ['एलेक्सी%']) '(यह' अज्ञात कॉलम 'फुलनाम' को 'जहां खंड' में फेंकता है " –

+7

मुझे ट्रिपल टिप्पणी के लिए खेद है। इस व्यवहार का कारण यह है कि डैंजो निश्चित रूप से पूर्णनाम को पास करता है उपनाम, जो MySQL के साथ काम नहीं करता है। यह 'हैविंग'-क्लॉज में काम करेगा, लेकिन ऐसा लगता है कि Django द्वारा समर्थित नहीं है। इसके बजाय, मैं निम्नलिखित (बहुत सुंदर नहीं) समझौता का उपयोग कर रहा हूं: 'मॉडल। Person.objects.extra (जहां = ["CONCAT (firstName, '', नाम) पसंद% s"], पैराम्स = ['Alexei%'])। आपके उत्तर के लिए धन्यवाद। –

1

मैं एक कस्टम सकल समारोह को लागू करने से इस हल:

आप fullName का उपयोग कर WHERE करने के लिए extra() जोड़ सकते हैं। इस मामले में मैचों के लिए फ़िल्टर/खोज करने में सक्षम होने के लिए मुझे व्यक्तिगत फ़ील्ड को सड़क के पते में जोड़ना होगा। निम्न समग्र फ़ंक्शन एक SQL CONCAT_WS निष्पादित करने के लिए एक फ़ील्ड और एक या अधिक निर्दिष्ट करने की अनुमति देता है।

संपादित 3 अगस्त 2015:

https://stackoverflow.com/a/19529861/3230522 से बटोरा विवरण के साथ एक बेहतर कार्यान्वयन। पिछला कार्यान्वयन असफल हो जाएगा यदि क्वेरीसेट को सबक्वायरी में इस्तेमाल किया गया था। तालिका के नाम अब सही हैं, हालांकि मुझे लगता है कि यह एक ही तालिका से कॉलम के संयोजन के लिए काम करता है।

from django.db.models import Aggregate 
from django.db.models.sql.aggregates import Aggregate as SQLAggregate 

class SqlAggregate(SQLAggregate): 
    sql_function = 'CONCAT_WS' 
    sql_template = u'%(function)s(" ", %(field)s, %(columns_to_concatenate)s)' 

    def as_sql(self, qn, connection): 
     self.extra['columns_to_concatenate'] = ', '.join(
     ['.'.join([qn(self.col[0]), qn(c.strip())]) for c in self.extra['with_columns'].split(',')]) 
     return super(SqlAggregate, self).as_sql(qn, connection) 

class Concatenate(Aggregate): 
    sql = SqlAggregate 

    def __init__(self, expression, **extra): 
     super(Concatenate, self).__init__(
      expression, 
      **extra) 

    def add_to_query(self, query, alias, col, source, is_summary): 

     aggregate = self.sql(col, 
         source=source, 
         is_summary=is_summary, 
         **self.extra) 

     query.aggregates[alias] = aggregate 
0

प्रस्तावित समाधान नीचे दिए गए कोड में पोस्टग्रेस्क्ल और जेएसओएनबी फ़ील्ड के साथ बहुत अच्छा काम करता है। केवल 'रिकॉर्ड' जेसनबी फ़ील्ड के तहत 'पार्टनर' कुंजी है, जो रिकॉर्ड हैं:

query_partner = "select key->>'partner' from accounting_subaccount " \ 
       "where accounting_subaccount.id = subaccount_id and key ? 'partner'" 
qs = queryset.extra(select={'partner': query_partner}, where=["key ? 'partner'"]) 
संबंधित मुद्दे