2010-06-03 12 views
8

के साथ संख्यात्मक मान का ऑर्डर करना मैं ऐसी परिस्थिति में हूं जहां मुझे सड़क पते को स्टोर करने के लिए उपयोग किए जाने वाले चारफ़िल्फ़ द्वारा ऑब्जेक्ट्स की एक बड़ी सूची आउटपुट करनी होगी।Django: order_by

मेरी समस्या यह है कि स्पष्ट रूप से डेटा ASCII कोड द्वारा आदेश दिया जाता है क्योंकि यह अनुमानित परिणामों के साथ एक चरफील्ड है .. यह इस तरह की संख्याओं को क्रमबद्ध करता है;

1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21.... 

अब स्पष्ट कदम (IntegerField मान लें) Charfield उचित क्षेत्र प्रकार बदलने के लिए, लेकिन यह काम नहीं कर सकता है, क्योंकि कुछ पता अपार्टमेंट हो सकता है .. "128A" जैसा होगा।

मैं वास्तव में नहीं जानता कि मैं कैसे आदेश कर सकते हैं इस ठीक से ..

+0

यदि आप इस के लिए एक समाधान पाया जानने के लिए उत्सुक। बहुत धन्यवाद। एन –

उत्तर

15

आप यकीन है कि वहाँ क्षेत्र में केवल पूर्णांक हैं कर रहे हैं, तो आप उस से extra विधि के माध्यम से एक पूर्णांक के रूप में यह कास्ट करने के लिए डेटाबेस, और आदेश मिल सकता है:

MyModel.objects.extra(
    select={'myinteger': 'CAST(mycharfield AS INTEGER)'} 
).order_by('myinteger') 
+1

सभी पते एक संख्या से शुरू नहीं होते हैं। यह दृष्टिकोण "मेरे चार क्षेत्रों में संख्याएं" के विशेष मामले के लिए काम करता है, लेकिन मिश्रित डेटा को सॉर्ट करने में विफल रहेगा। –

+0

अतिरिक्त का बहुत ही रोचक उपयोग, मैं शायद ही कभी उस विधि के साथ खेलता हूं .. लेकिन दुर्भाग्य से मेरी स्थिति में यह काम नहीं कर रहा है। –

+2

यदि आपका MYSQL संस्करण इसका समर्थन नहीं करता है तो INTEGER के बजाय 'हस्ताक्षर' या 'UNSIGNED' का उपयोग करें। आपकी टिप्पणी के लिए – Adriaan

2

समस्या आप के खिलाफ कर रहे हैं काफी कैसे फ़ाइल नाम जब फ़ाइल नाम से छँटाई का आदेश दिया करने के लिए समान है। वहां, आप "12 Foo.mp3" से पहले दिखने के लिए "2 Foo.mp3" चाहते हैं।

एक सामान्य दृष्टिकोण संख्याओं की एक निश्चित संख्या में विस्तार करने के लिए संख्याओं को "सामान्यीकृत" करना है, और फिर सामान्यीकृत फ़ॉर्म के आधार पर सॉर्ट करना है। यही है, सॉर्टिंग के प्रयोजनों के लिए, "2 Foo.mp3" "0000000002 Foo.mp3" तक विस्तारित हो सकता है।

Django सीधे यहां आपकी सहायता नहीं करेगा। आप या तो "सामान्यीकृत" पते को संग्रहीत करने के लिए एक फ़ील्ड जोड़ सकते हैं, और डेटाबेस order_by है, या आप रिकॉर्ड्स की सूची सौंपने से पहले पता रिकॉर्ड पर अपने दृश्य में एक कस्टम सॉर्ट (या आपके द्वारा उपयोग किए जाने वाले सहायक में) कर सकते हैं एक टेम्पलेट के लिए।

3

महान टिप! इससे मेरा काम बनता है!

revisioned_objects = revisioned_objects.extra(select={'casted_object_id': 'CAST(object_id AS INTEGER)'}).extra(order_by = ['casted_object_id']) 
9

आप PostgreSQL (MySQL बारे में निश्चित नहीं) उपयोग कर रहे हैं आप सुरक्षित रूप से चार/पाठ फ़ील्ड पर निम्नलिखित कोड का उपयोग करें और कलाकारों त्रुटियों से बचने कर सकते हैं:: :) मेरा कोड यह है

MyModel.objects.extra(
    select={'myinteger': "CAST(substring(charfield FROM '^[0-9]+') AS INTEGER)"} 
).order_by('myinteger') 
+0

यह एक उत्कृष्ट सुझाव है! –

+0

यह सबसे अच्छा है यदि आपको स्ट्रिंग्स द्वारा क्रमबद्ध करना है, जिसमें पैटर्न हैं। [0-9] + ' – Ajoy

+0

मारियाडीबी के लिए वाक्यविन्यास होगा: "CAST (REGEXP_SUBSTR (name,'^[0-9] + ') एएस इंटेगर) "। धन्यवाद!! –

7

Django deprecateextra() विधि की कोशिश कर रहा है, लेकिन v1.10 में Cast() पेश किया है। SQLite (कम से कम) में, CAST10a के रूप में इस तरह के एक मूल्य के ले जा सकते हैं और पूर्णांक 10 करने के लिए इसे डाली जाएगी, ताकि आप कर सकते हैं:

from django.db.models import IntegerField 
from django.db.models.functions import Cast 

MyModel.objects.annotate(
    my_integer_field=Cast('my_char_field', IntegerField()) 
).order_by('my_integer_field', 'my_char_field') 

जो पहले संख्यानुसार सड़क संख्या के अनुसार क्रमबद्ध वस्तुओं तो वर्णानुक्रम वापस आ जाएगी, उदाहरण के लिए

class VersionRecordManager(models.Manager): 

    def get_queryset(self): 
     return super().get_queryset().extra(
      select={ 
       'natural_version': "string_to_array(version, '.')::int[]", 
      }, 
     ) 

    def available_versions(self): 
     return self.filter(available=True).order_by('-natural_version') 

    def last_stable(self): 
     return self.available_versions().filter(stable=True).first() 

class VersionRecord(models.Model): 
    objects = VersionRecordManager() 
    version = models.CharField(max_length=64, db_index=True) 
    available = models.BooleanField(default=False, db_index=True) 
    stable = models.BooleanField(default=False, db_index=True) 

मामले में आप गैर-संख्यात्मक अनुमति देना चाहते हैं: ...14, 15a, 15b, 16, 16a, 17...

+1

'कास्ट' '10a' जैसे मानों का समर्थन नहीं करता है। यदि यह एक प्राप्त करता है, तो यह 'डेटा त्रुटि: पूर्णांक के लिए अमान्य इनपुट वाक्यविन्यास' फेंकता है। django.db.models.expressions से 'आयात एफ, मूल्य, Func' ' queryset.annotate (my_integer_field = कास्ट ( : मैं मूल्य में सभी वर्णों कि नंबर नहीं हैं (PostgreSQL) को हटाने के द्वारा एक समाधान पाया समारोह (एफ ('my_char_field'), मूल्य ('[^ \ d]'), मूल्य (''), मूल्य ('जी'), समारोह = 'regexp_replace'), IntegerField()) ) ' – Filly

+1

@ फिली क्या आप पूरा उदाहरण दे सकते हैं जिसने त्रुटि फेंक दी? – practual

1

मामले में आप एक बिंदु के द्वारा अलग एकाधिक संख्याओं से मिलकर संस्करण संख्याओं को सॉर्ट करने की जरूरत है (उदाहरण के लिए 1.9.0, 1.10.0), यहाँ एक postgres-एकमात्र समाधान है वर्ण (जैसे 0.9.0 beta, 2.0.0 stable):

def get_queryset(self): 
    return super().get_queryset().extra(
     select={ 
      'natural_version': 
       "string_to_array(     " 
       " regexp_replace(     " # Remove everything except digits 
       "  version, '[^\d\.]+', '', 'g' " # and dots, then split string into 
       " ), '.'       " # an array of integers. 
       ")::int[]        " 
     } 
    ) 
संबंधित मुद्दे