Django 모델에서 mySQL ENUM 지정


92

Django 모델에서 ENUM을 지정하고 사용하려면 어떻게해야합니까?


4
Steve, MySQL ENUM 유형을 사용하려는 경우 Django가 지원을 제공하지 않는 한 운이 좋지 않습니다 (이 기능은 Django가 지원하는 모든 DB에서 사용할 수 없습니다). Paul이 제공 한 대답은 작동하지만 DB에서 유형을 정의 하지는 않습니다 .
dguaraglia

답변:


108

로부터 장고 문서 :

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

@Strayer 예, 이것은 모델 양식을 사용하는 경우에만 유용하다고 생각합니다
Acute

권장되는 Django 스타일은 문자가 상수 여야 함을 의미합니다. docs.djangoproject.com/en/dev/internals/contributing/…
Michael Scheper

11
@Carl Meyer가 그의 답변에서 말했듯이 이것은 데이터베이스에 ENUM 열을 생성하지 않습니다. VARCHAR 또는 INTEGER 열을 생성하므로 실제로 질문에 대답하지 않습니다.
Ariel

정수 필드로 선택 기능을 추가 할 수 있습니까? @fulmicoton
Ilyas 카림

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에 두 번째 매개 변수 인 connection을 추가해야합니다.
Hans Lawrenz

2
그러면 codecatelog는 어떻게 되었습니까? Lokos가 좋은 생각이었을 것 같은데 .... 나는 지금 404를 얻습니다-심지어 루트 페이지에서도.
Danny Staple

33

은 Using choices를 상기 ENUM DB 유형을 사용하지 않습니다 매개 변수를; choicesCharField 또는 IntegerField와 함께 사용하는지 여부에 따라 VARCHAR 또는 INTEGER를 만듭니다. 일반적으로 이것은 괜찮습니다. ENUM 유형이 데이터베이스 수준에서 사용되는 것이 중요한 경우 다음 세 가지 옵션이 있습니다.

  1. "./manage.py sql appname"을 사용하여 Django가 생성 한 SQL을 확인하고 수동으로 수정하여 ENUM 유형을 사용하고 직접 실행합니다. 먼저 수동으로 테이블을 생성하면 "./manage.py syncdb"가 엉망이되지 않습니다.
  2. DB를 생성 할 때마다 수동으로이 작업을 수행하지 않으려면 appname / sql / modelname.sql에 사용자 지정 SQL을 넣어 적절한 ALTER TABLE 명령을 수행하십시오.
  3. 사용자 정의 필드 유형을 작성 하고 db_type 메소드를 적절하게 정의하십시오.

이러한 옵션을 사용하여 데이터베이스 간 이식성에 대한 영향을 처리하는 것은 사용자의 책임입니다. 옵션 2에서는 데이터베이스 백엔드 별 사용자 지정 SQL 을 사용하여 ALTER 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:

이것은 실제로 데이터베이스에 열거 형을 저장하지는 않지만 열거 형을 구현하는 또 다른 훌륭하고 쉬운 방법입니다.

그러나 '값'(숫자 일 수 있음)을 사용해야하는 최고 등급 답변과 달리 기본값을 쿼리하거나 지정할 때마다 '라벨'을 참조 할 수 있습니다.


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을 만들어야합니다. Reff 8.7. 열거 유형 나는 @David의 트릭을 시도했으며 MySQL에서는 잘 작동하지만 PostgrSQL에서는 오류가 발생 'type "enum" does not exist LINE 1: ....tablename" ADD COLUMN "select_user" ENUM('B', ...'합니다.
Grijesh Chauhan 2014


3

현재 두 개의 github 프로젝트가 추가되어 있지만 구현 방법을 정확히 살펴 보지는 않았습니다.

  1. Django-EnumField :
    재사용 가능한 열거 형 및 전환 유효성 검사와 함께 열거 형 Django 모델 필드 (IntegerField 사용)를 제공합니다.
  2. Django-EnumFields :
    이 패키지를 사용하면 Django에서 실제 Python (PEP435 스타일) 열거 형을 사용할 수 있습니다.

DB enum 유형을 사용하지 않는다고 생각하지만 처음 에는 작동 중입니다.


1

Django 3.0은 Enum을 기본적으로 지원합니다.

로부터 문서 :

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,
    )

이제 데이터베이스 수준에서 선택 사항을 적용하지 않습니다 . 이것은 Python 전용 구성입니다. 데이터베이스에서 이러한 값을 적용하려면이를 데이터베이스 제약 조건과 결합 할 수 있습니다.

class Student(models.Model):
    ...

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

-2

models.py 파일 맨 위에 가져 오기를 수행 한 후 다음 행을 추가하십시오.

    enum = lambda *l: [(s,_(s)) for s in l]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.