python - Django में केस असंवेदनशील अद्वितीय मॉडल फ़ील्ड?




postgresql model (5)

Django 1.11 के रूप में, आप CITextField , Citext प्रकार द्वारा समर्थित केस-असंवेदनशील पाठ के लिए पोस्टग्रेज-विशिष्ट फ़ील्ड का उपयोग कर सकते हैं।

from django.db import models
from django.contrib.postgres.fields import CITextField

class Something(models.Model):
    foo = CITextField()

Django CIEmailField और CICharField भी प्रदान करता है, जो CIEmailField और CICharField केस-असंवेदनशील संस्करण हैं।

मेरे पास मूल रूप से एक उपयोगकर्ता नाम अद्वितीय है (केस असंवेदनशील), लेकिन उपयोगकर्ता द्वारा प्रदान किए जाने पर प्रदर्शित होने पर मामला मायने रखता है।

मेरी निम्नलिखित ज़रूरतें हैं:

  • फ़ील्ड CharField संगत है
  • क्षेत्र अद्वितीय है, लेकिन मामला असंवेदनशील है
  • फ़ील्ड को खोजे जाने योग्य अनदेखा करने की आवश्यकता होती है (यानी, आसानी से भुलाए जाने वाले आईएक्सएक्ट का उपयोग करने से बचें)
  • फ़ील्ड को अक्षुण्ण रखा जाता है
  • डेटाबेस स्तर पर अधिमानतः लागू किया गया
  • अधिमानतः एक अतिरिक्त क्षेत्र के भंडारण से बचें

क्या यह Django में संभव है?

एकमात्र समाधान जो मैं आया था, वह है "किसी तरह" मॉडल प्रबंधक को ओवरराइड करना, एक अतिरिक्त फ़ील्ड का उपयोग करना, या हमेशा खोज में 'iexact' का उपयोग करना।

मैं Django 1.3 और PostgreSQL 8.4.2 पर हूं।


आप इसके बजाय citext postgres प्रकार का उपयोग कर सकते हैं और किसी भी प्रकार के iexact के साथ परेशान नहीं कर सकते हैं। बस मॉडल में एक नोट करें कि अंतर्निहित क्षेत्र असंवेदनशील है। बहुत आसान उपाय।


चूंकि एक उपयोगकर्ता नाम हमेशा लोअरकेस होता है, इसलिए इसे Django में एक कस्टम लोअरकेस मॉडल फ़ील्ड का उपयोग करने की अनुशंसा की जाती है। एक्सेस और कोड- fields.py की आसानी के लिए, अपने ऐप फ़ोल्डर में एक नई फ़ाइल fields.py बनाएं।

from django.db import models
from django.utils.six import with_metaclass

# Custom lowecase CharField

class LowerCharField(with_metaclass(models.SubfieldBase, models.CharField)):
    def __init__(self, *args, **kwargs):
        self.is_lowercase = kwargs.pop('lowercase', False)
        super(LowerCharField, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        value = super(LowerCharField, self).get_prep_value(value)
        if self.is_lowercase:
            return value.lower()
        return value

models.py में उपयोग

from django.db import models
from your_app_name.fields import LowerCharField

class TheUser(models.Model):
    username = LowerCharField(max_length=128, lowercase=True, null=False, unique=True)

अंतिम नोट : आप डेटाबेस में लोअरकेस मानों को संग्रहीत करने के लिए इस विधि का उपयोग कर सकते हैं, और __iexact बारे में चिंता न करें।


मॉडल प्रबंधक को ओवरराइड करने के साथ, आपके पास दो विकल्प हैं। पहले सिर्फ एक नया लुकअप तरीका बनाना है:

class MyModelManager(models.Manager):
   def get_by_username(self, username):
       return self.get(username__iexact=username)

class MyModel(models.Model):
   ...
   objects = MyModelManager()

फिर, आप get_by_username('blah') उपयोग get(username='blah') get_by_username('blah') बजाय करें, और आपको iexact भूलने की चिंता करने की आवश्यकता नहीं है। बेशक इसके बाद आपको get_by_username का उपयोग करना याद get_by_username

दूसरा विकल्प बहुत अधिक हैकर और दृढ़ है। मुझे यह सुझाव देने में भी संकोच हो रहा है, लेकिन पूर्णता के लिए, मैं करूंगा: filter ओवरराइड करें और ऐसे get कि यदि आप उपयोगकर्ता नाम से क्वेरी करते समय iexact भूल जाते हैं, तो यह आपके लिए इसे जोड़ देगा।

class MyModelManager(models.Manager):
    def filter(self, **kwargs):
        if 'username' in kwargs:
            kwargs['username__iexact'] = kwargs['username']
            del kwargs['username']
        return super(MyModelManager, self).filter(**kwargs)

    def get(self, **kwargs):
        if 'username' in kwargs:
            kwargs['username__iexact'] = kwargs['username']
            del kwargs['username']
        return super(MyModelManager, self).get(**kwargs)

class MyModel(models.Model):
   ...
   objects = MyModelManager()

मूल मिश्रित-केस स्ट्रिंग को एक सादे पाठ कॉलम में संग्रहीत करें । डेटा प्रकार के text उपयोग करें या varchar बिना लंबाई संशोधक के बजाय varchar(n) । वे अनिवार्य रूप से समान हैं, लेकिन varchar (n) के साथ आपको एक मनमाना लंबाई सीमा निर्धारित करनी होगी, यदि बाद में आप बदलना चाहें तो दर्द हो सकता है। इसके बारे में और अधिक पढ़ें मैनुअल में या पीटर Eisentraut @ serverfault.SE द्वारा इस संबंधित उत्तर में

lower(string) पर एक कार्यात्मक अद्वितीय सूचकांक बनाएं। यहाँ प्रमुख बात यह है कि:

CREATE UNIQUE INDEX my_idx ON mytbl(lower(name));

यदि आप एक मिश्रित मामले के नाम को INSERT करने का प्रयास करते हैं जो पहले से ही निचले मामले में है तो आपको एक अद्वितीय कुंजी उल्लंघन त्रुटि मिलती है।
तेजी से समानता खोज के लिए इस तरह एक क्वेरी का उपयोग करें:

SELECT * FROM mytbl WHERE lower(name) = 'foo' --'foo' is lower case, of course.

इंडेक्स में उसी अभिव्यक्ति का उपयोग करें (ताकि क्वेरी योजनाकार संगतता को पहचानता है) और यह बहुत तेज़ होगा।

एक तरफ के रूप में: आप PostgreSQL के अधिक हाल के संस्करण में अपग्रेड करना चाह सकते हैं। 8.4.2 से बहुत सारे महत्वपूर्ण सुधार हुए हैंआधिकारिक Postgres संस्करण साइट पर अधिक।





model