2013-02-27 3 views
27

क्वेरी करने के लिए "कुल अंतिम" जोड़ना मैं पोस्टग्रेस्क्ल के "नलर्स अंतिम" विकल्प का उपयोग करके एक मॉडल को सॉर्ट करना चाहता हूं। यह कैसे किया जा सकता है?Django:

मैं की तरह

MyModel.objects.all().extra(order_by=('-price', 'NULLS LAST'))

कुछ करने की कोशिश की लेकिन मैं

उत्तर

15

निकटतम बात मैं मिल गया है दो पर यह क्या कर रहा है "फ़ील्ड में कीवर्ड को हल नहीं किया जा सकता 'पिछले nulls'"

मिल कदम। आबादी वाले क्षेत्र पर और फिर nulls पर पहले आदेश:

वाया this सार (जो खुद इन django logs के माध्यम से):

all_projects = Project.objects.select_related().filter(
    company=company).order_by('-date_due') 

q = all_projects.extra(select={'date_due_null': 'date_due is null'}) 
q = q.extra(order_by=['date_due_null']) 
print q.query 

गुड लक।

+0

धन्यवाद। यह वास्तव में सही समाधान नहीं है लेकिन थोड़े काम करता है – GabiMe

+2

आपका स्वागत है। मुझे नहीं लगता कि इसके लिए एक सही समाधान है, या कम से कम एक जो डीजेगो द्वारा सीधे विचार किया गया है, [यह Google समूह पोस्ट] दिया गया है (https://groups.google.com/d/msg/django-users/sxbpqmkRyCU/ QUYjX3niCOEJ) मैल्कम ट्रेडिनिक द्वारा। – Mariano

20

यदि आप पारदर्शी रूप से और सभी कॉलम पर करना चाहते हैं, तो आप एसक्यूएल पीढ़ी को फिर से परिभाषित कर सकते हैं। ऐसा करने के लिए, कस्टम कंपाइलर का उपयोग करने के लिए आपको अपनी कस्टम क्वेरी वापस करने के लिए अपने कस्टम क्वेरीसेट को वापस करने के लिए अपना स्वयं का प्रबंधक होना होगा। उस के लिए मेरे कोड है कि तरह लग रहा है (Django 1.5):

from django.db import models, connections 

class NullsLastQuery(models.sql.query.Query): 
    """ 
    Query that uses custom compiler, 
    to utilize PostgreSQL feature of setting position of NULL records 
    """ 
    def get_compiler(self, using=None, connection=None): 
     if using is None and connection is None: 
      raise ValueError("Need either using or connection") 
     if using: 
      connection = connections[using] 

     # defining that class elsewhere results in import errors 
     from django.db.models.sql.compiler import SQLCompiler 
     class NullsLastSQLCompiler(SQLCompiler): 
      def get_ordering(self): 
       result, group_by = super(NullsLastSQLCompiler, self 
        ).get_ordering() 
       if self.connection.vendor == 'postgresql' and result: 
        result = [line + " NULLS LAST" for line in result] 
       return result, group_by 

     return NullsLastSQLCompiler(self, connection, using) 

class NullsLastQuerySet(models.query.QuerySet): 
    def __init__(self, model=None, query=None, using=None): 
     super(NullsLastQuerySet, self).__init__(model, query, using) 
     self.query = query or NullsLastQuery(self.model) 

class NullsLastManager(models.Manager): 
    def get_query_set(self): 
     return NullsLastQuerySet(self.model, using=self._db) 

class YourModel(models.Model): 
    objects = NullsLastManager() 
+5

यह थोड़ा बुरा है, लेकिन शानदार है। –

9

Django 1.9 (और संभवतः 1.8) आप इस का उपयोग कर सकते के लिए:

from django.db import connections, models 
from django.db.models.sql.compiler import SQLCompiler 


class NullsLastSQLCompiler(SQLCompiler): 
    def get_order_by(self): 
     result = super().get_order_by() 
     if result and self.connection.vendor == 'postgresql': 
      return [(expr, (sql + ' NULLS LAST', params, is_ref)) 
        for (expr, (sql, params, is_ref)) in result] 
     return result 


class NullsLastQuery(models.sql.query.Query): 
    """Use a custom compiler to inject 'NULLS LAST' (for PostgreSQL).""" 

    def get_compiler(self, using=None, connection=None): 
     if using is None and connection is None: 
      raise ValueError("Need either using or connection") 
     if using: 
      connection = connections[using] 
     return NullsLastSQLCompiler(self, connection, using) 


class NullsLastQuerySet(models.QuerySet): 
    def __init__(self, model=None, query=None, using=None, hints=None): 
     super().__init__(model, query, using, hints) 
     self.query = query or NullsLastQuery(self.model) 

और फिर अपने मॉडल (ओं) पर:

objects = NullsLastQuerySet.as_manager() 

यह टिम से https://stackoverflow.com/a/17077587/15690 में उत्तर पर आधारित है।

Django को इसके लिए समर्थन जोड़ने का टिकट फिर से खोला गया है: https://code.djangoproject.com/ticket/13312

+0

आपने मेरा दिन बचाया। – levi

+0

क्या आपके पास अंत में खाली तार रखने के लिए कार्यक्षमता को शामिल करने के बारे में कोई विचार है? – Duncan

+1

@ डंकन इस समय के लिए भुगतान किए बिना नहीं, क्षमा करें ..;) – blueyed

7

यह शायद उपलब्ध नहीं था जब प्रश्न पूछा गया था, लेकिन Django 1.8 के बाद से मुझे लगता है कि यह सबसे अच्छा समाधान है:

from django.db.models.functions import Coalesce, Value 
MyModel.objects.all().annotate(price_null= 
    Coalesce('price', Value(-100000000)).order_by('-price_null') 

Coalesce पहली गैर शून्य मान का चयन करता है, तो आप के लिए एक मूल्य price_null बनाने जिस क्रम से केवल कीमत है लेकिन null-100000000 (या +?) द्वारा प्रतिस्थापित किया गया है।

+0

यह वास्तव में एक महान हैक है क्योंकि इसे शून्य अंतिम अनुक्रमणिका बनाने और – valignatev

+1

@valentjedi पूछताछ के लिए ऐसी चीजों को बनाने की आवश्यकता नहीं है, यह नहीं है कोलेसेस ('मूल्य', मूल्य (-100000000) 'के साथ एक अभिव्यक्ति सूचकांक की आवश्यकता है? यह एक अंतिम अंतिम सूचकांक बनाने जैसा ही होगा। यहां http://dba.stackexchange.com/a/99009 कोई भी वही कहता है मैं कह रहा हूं – jperelli

+0

@ जेपेरेली आप वास्तव में सही हैं। लेकिन मेरे मामले में यह हैक नल को अंतिम जोड़ने से तेज़ था इसलिए यह मुझे संतुष्ट करता था। – valignatev

12

यह कार्यक्षमता Django 1.11 (अभी भी बीटा में लिखने के रूप में) में जोड़ा गया है।

https://docs.djangoproject.com/en/dev/releases/1.11/

जोड़ा गया nulls_first और Expression.asc को nulls_last मानकों() और desc() शून्य मान के आदेश को नियंत्रित करने के।