एक Django मॉडल में एक MySQL ENUM निर्दिष्ट करना


92

मैं Django मॉडल में ENUM का उपयोग करने और निर्दिष्ट करने के बारे में कैसे जा सकता हूं?


4
स्टीव, यदि आपका मतलब MySQL ENUM प्रकार का उपयोग करना है, तो आप भाग्य से बाहर हैं, जहाँ तक मुझे पता है कि Django उस के लिए समर्थन प्रदान नहीं करता है (यह सुविधा Django द्वारा समर्थित सभी DBs में उपलब्ध नहीं है)। पॉल द्वारा प्रदान किया गया जवाब काम करता है, लेकिन यह डीबी के प्रकार को परिभाषित नहीं करेगा
डेंगारागलिया

जवाबों:


108

से Django प्रलेखन :

MAYBECHOICE = (
    ('y', 'Yes'),
    ('n', 'No'),
    ('u', 'Unknown'),
)

और आप अपने मॉडल में एक charfield परिभाषित करते हैं:

married = models.CharField(max_length=1, choices=MAYBECHOICE)

यदि आप अपने db में अक्षर रखना पसंद नहीं करते हैं तो आप पूर्णांक फ़ील्ड के साथ भी ऐसा कर सकते हैं।

उस मामले में, अपनी पसंद को फिर से लिखें:

MAYBECHOICE = (
    (0, 'Yes'),
    (1, 'No'),
    (2, 'Unknown'),
)

8
यह "झूठे" मूल्यों को सहेजने से रोकता नहीं है अगर पहले साफ नहीं किया जाता है, तो क्या यह करता है?
स्ट्रेटर

@Strayer हाँ, मुझे लगता है कि यह केवल मॉडल रूपों का उपयोग करने के लिए उपयोगी है
एक्यूट

ध्यान दें कि अनुशंसित Django शैली का अर्थ है कि पात्रों को स्थिरांक होना चाहिए: docs.djangoproject.com/en/dev/internals/contributing/…
माइकल शेपर

11
जैसा @Carl Meyer ने अपने उत्तर में कहा, यह डेटाबेस में ENUM कॉलम नहीं बनाता है। यह VARCHAR या INTEGER कॉलम बनाता है, इसलिए यह वास्तव में प्रश्न का उत्तर नहीं देता है।
एरियल

क्या मैं पूर्णांक फ़ील्ड के साथ विकल्प सुविधा जोड़ सकता हूं? @fulmicoton
इलियास करीम

36
from django.db import models

class EnumField(models.Field):
    """
    A field class that maps to MySQL's ENUM type.

    Usage:

    class Card(models.Model):
        suit = EnumField(values=('Clubs', 'Diamonds', 'Spades', 'Hearts'))

    c = Card()
    c.suit = 'Clubs'
    c.save()
    """
    def __init__(self, *args, **kwargs):
        self.values = kwargs.pop('values')
        kwargs['choices'] = [(v, v) for v in self.values]
        kwargs['default'] = self.values[0]
        super(EnumField, self).__init__(*args, **kwargs)

    def db_type(self):
        return "enum({0})".format( ','.join("'%s'" % v for v in self.values) )

2
Django 1.2 के अनुसार, आपको db_type def में एक दूसरा पैरामीटर, कनेक्शन जोड़ना होगा।
हंस लॉरेनज़

2
जो कुछ भी codecatelog तब हुआ? लोकोस की तरह यह एक अच्छा विचार हो सकता था .... मुझे अब एक 404 मिलता है - रूट पेज के लिए भी।
डैनी स्टेपल

33

का उपयोग करते हुए choicesEnum db प्रकार का उपयोग नहीं होगा पैरामीटर; यह सिर्फ एक VARCHAR या choicesINTEGER का निर्माण करेगा, जो इस बात पर निर्भर करता है कि आप एक CharField या IntegerField का उपयोग करते हैं या नहीं। आम तौर पर, यह ठीक है। यदि आपके लिए यह महत्वपूर्ण है कि डेटाबेस स्तर पर ENUM प्रकार का उपयोग किया जाए, तो आपके पास तीन विकल्प हैं:

  1. SQL Django जेनरेट करने के लिए "./manage.py sql appname" का उपयोग करें, मैन्युअल रूप से ENUM प्रकार का उपयोग करने के लिए इसे संशोधित करें, और इसे स्वयं चलाएं। यदि आप पहले मैन्युअल रूप से तालिका बनाते हैं, तो "./manage.py syncdb" इसके साथ गड़बड़ नहीं करेगा।
  2. यदि आप अपने DB को जेनरेट करने के लिए हर बार इसे मैन्युअल रूप से नहीं करना चाहते हैं, तो उपयुक्त ALTER TABLE कमांड करने के लिए कुछ कस्टम SQL को appname / sql / modelname.sql में डालें।
  3. एक कस्टम फ़ील्ड प्रकार बनाएं और db_type पद्धति को उचित रूप से परिभाषित करें।

इनमें से किसी भी विकल्प के साथ, क्रॉस-डेटाबेस पोर्टेबिलिटी के निहितार्थों से निपटना आपकी ज़िम्मेदारी होगी। विकल्प 2 में, आप डेटाबेस-बैकएंड-विशिष्ट कस्टम SQL का उपयोग कर सकते हैं ताकि यह सुनिश्चित हो सके कि आपका TABLE केवल MySQL पर चलता है। विकल्प 3 में, आपकी db_type विधि को डेटाबेस इंजन की जाँच करने और db स्तंभ प्रकार को उस डेटाबेस में सेट करने की आवश्यकता होगी जो वास्तव में उस डेटाबेस में मौजूद है।

अद्यतन : चूंकि Django 1.7 में माइग्रेशन फ्रेमवर्क जोड़ा गया था, इसलिए विकल्प 1 और 2 ऊपर पूरी तरह से अप्रचलित हैं। विकल्प 3 वैसे भी हमेशा सबसे अच्छा विकल्प था। विकल्प 1/2 के नए संस्करण में एक जटिल कस्टम माइग्रेशन शामिल होगा SeparateDatabaseAndState- लेकिन वास्तव में आप विकल्प 3 चाहते हैं।


10

http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/

class Entry(models.Model):
    LIVE_STATUS = 1
    DRAFT_STATUS = 2
    HIDDEN_STATUS = 3
    STATUS_CHOICES = (
        (LIVE_STATUS, 'Live'),
        (DRAFT_STATUS, 'Draft'),
        (HIDDEN_STATUS, 'Hidden'),
    )
    # ...some other fields here...
    status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS)

live_entries = Entry.objects.filter(status=Entry.LIVE_STATUS)
draft_entries = Entry.objects.filter(status=Entry.DRAFT_STATUS)

if entry_object.status == Entry.LIVE_STATUS:

यह enums लागू करने का एक और अच्छा और आसान तरीका है, हालांकि यह वास्तव में डेटाबेस में enums को सहेजता नहीं है।

हालाँकि, यह आपको 'लेबल' को संदर्भित करने की अनुमति देता है जब भी टॉप-रेटेड उत्तर के विरोध के रूप में डिफॉल्ट को क्वेरी या निर्दिष्ट करता है जहां आपको 'मूल्य' (जो एक संख्या हो सकती है) का उपयोग करना होगा।


9

choicesफ़ील्ड पर सेट करने से Django के अंत पर कुछ सत्यापन की अनुमति मिल जाएगी, लेकिन यह डेटाबेस के अंत पर किसी भी प्रकार के किसी भी प्रकार को परिभाषित नहीं करेगा

जैसा कि दूसरों ने उल्लेख किया है, समाधान db_typeएक कस्टम फ़ील्ड पर निर्दिष्ट करना है।

यदि आप SQL बैकएंड (जैसे MySQL) का उपयोग कर रहे हैं, तो आप ऐसा कर सकते हैं:

from django.db import models


class EnumField(models.Field):
    def __init__(self, *args, **kwargs):
        super(EnumField, self).__init__(*args, **kwargs)
        assert self.choices, "Need choices for enumeration"

    def db_type(self, connection):
        if not all(isinstance(col, basestring) for col, _ in self.choices):
            raise ValueError("MySQL ENUM values should be strings")
        return "ENUM({})".format(','.join("'{}'".format(col) 
                                          for col, _ in self.choices))


class IceCreamFlavor(EnumField, models.CharField):
    def __init__(self, *args, **kwargs):
        flavors = [('chocolate', 'Chocolate'),
                   ('vanilla', 'Vanilla'),
                  ]
        super(IceCreamFlavor, self).__init__(*args, choices=flavors, **kwargs)


class IceCream(models.Model):
    price = models.DecimalField(max_digits=4, decimal_places=2)
    flavor = IceCreamFlavor(max_length=20)

ठीक से बनाया गया था, syncdbयह देखने के लिए अपनी तालिका को चलाएं और निरीक्षण करें ENUM

mysql> SHOW COLUMNS IN icecream;
+--------+-----------------------------+------+-----+---------+----------------+
| Field  | Type                        | Null | Key | Default | Extra          |
+--------+-----------------------------+------+-----+---------+----------------+
| id     | int(11)                     | NO   | PRI | NULL    | auto_increment |
| price  | decimal(4,2)                | NO   |     | NULL    |                |
| flavor | enum('chocolate','vanilla') | NO   |     | NULL    |                |
+--------+-----------------------------+------+-----+---------+----------------+

बहुत मददगार जवाब! लेकिन यह PostgreSQL के लिए काम नहीं करेगा। कारण PostgreSQL ENUM डिफ़ॉल्ट रूप से समर्थन नहीं करता है। PostgreSQL में सबसे पहले हमें CREATE DOMAIN या CREATE TYPE बनाना होगा। रीफ 8.7। Enumerated Types मैंने कोशिश की @ David की ट्रिक और यह MySQL के साथ ठीक काम कर रहा है लेकिन PostgrSQL में एंड-अप एक त्रुटि के साथ काम करता है 'type "enum" does not exist LINE 1: ....tablename" ADD COLUMN "select_user" ENUM('B', ...'
बृजेश चौहान

6

यदि आप वास्तव में अपने डेटाबेस ENUM प्रकार का उपयोग करना चाहते हैं:

  1. Django 1.x का उपयोग करें
  2. अपने आवेदन को पहचानें केवल कुछ डेटाबेस पर काम करेंगे।
  3. इस दस्तावेज़ पृष्ठ के माध्यम से पहेली: http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

सौभाग्य!


3

वर्तमान में इन्हें जोड़ने के आधार पर दो गितुब परियोजनाएं हैं, हालांकि मैंने इस बात पर ध्यान नहीं दिया है कि वे कैसे कार्यान्वित की जाती हैं:

  1. Django-EnumField :
    पुन: प्रयोज्य Enums और संक्रमण सत्यापन के साथ एक Enumeration Django मॉडल फ़ील्ड (IntegerField का उपयोग करके) प्रदान करता है।
  2. Django-EnumFields :
    इस पैकेज की मदद से आप Django के साथ असली पायथन (PEP435- शैली) का उपयोग कर सकते हैं।

मुझे नहीं लगता कि या तो DB enum प्रकारों का उपयोग करें, लेकिन वे पहले एक के लिए काम कर रहे हैं ।


1

Django 3.0 ने Enums के लिए बिल्ट-इन सपोर्ट दिया है

से प्रलेखन :

from django.utils.translation import gettext_lazy as _

class Student(models.Model):

    class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')

    year_in_school = models.CharField(
        max_length=2,
        choices=YearInSchool.choices,
        default=YearInSchool.FRESHMAN,
    )

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

class Student(models.Model):
    ...

    class Meta:
        constraints = [
            CheckConstraint(
                check=Q(year_in_school__in=YearInSchool.values),
                name="valid_year_in_school")
        ]

-2

आपके आयात करने के बाद इस मॉडल के शीर्ष पर आपकी फ़ाइल का नाम जुड़ जाएगा:

    enum = lambda *l: [(s,_(s)) for s in l]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.