장고에서 "선택" 필드 옵션을 올바르게 사용하는 방법
저는 여기서 튜토리얼을 읽고 있습니다: https://docs.djangoproject.com/en/1.5/ref/models/fields/ #books 그리고 저는 사용자가 그가 태어난 달을 선택할 수 있는 상자를 만들려고 노력하고 있습니다.내가 노력한 것은
MONTH_CHOICES = (
(JANUARY, "January"),
(FEBRUARY, "February"),
(MARCH, "March"),
....
(DECEMBER, "December"),
)
month = CharField(max_length=9,
choices=MONTHS_CHOICES,
default=JANUARY)
이거 맞는건가요?제가 읽고 있던 튜토리얼에서 어떤 이유에서인지 그들은 먼저 변수를 만들었다는 것을 알 수 있습니다.
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
그들은 왜 그런 변수들을 만들었을까요?또한 MONGS_CHOICE는 People이라는 모델에 있는데, 제가 제공한 코드는 "People"이라는 데이터베이스에 "Months Choices" 열을 만들고 사용자가 월 중에서 클릭하여 양식을 제출한 후 몇 월에 태어났는지 표시합니까?
저는 아무도 실제로 첫 번째 질문에 대답하지 않았다고 생각합니다.
그들은 왜 그런 변수들을 만들었을까요?
그러한 변수들이 꼭 필요한 것은 아닙니다.사실입니다.다음과 같은 작업을 완벽하게 수행할 수 있습니다.
MONTH_CHOICES = (
("JANUARY", "January"),
("FEBRUARY", "February"),
("MARCH", "March"),
# ....
("DECEMBER", "December"),
)
month = models.CharField(max_length=9,
choices=MONTH_CHOICES,
default="JANUARY")
변수를 사용하는 것이 더 나은 이유는 무엇입니까?오류 방지 및 논리 분리.
JAN = "JANUARY"
FEB = "FEBRUARY"
MAR = "MAR"
# (...)
MONTH_CHOICES = (
(JAN, "January"),
(FEB, "February"),
(MAR, "March"),
# ....
(DEC, "December"),
)
이제 새 모델 인스턴스를 생성하는 보기가 있다고 상상해 보십시오.이렇게 하는 대신:
new_instance = MyModel(month='JANUARY')
다음과 같은 작업을 수행할 작업:
new_instance = MyModel(month=MyModel.JAN)
첫 번째 옵션에서는 값을 하드 코딩하고 있습니다.입력할 수 있는 값 집합이 있으면 코드화할 때 해당 옵션을 제한해야 합니다.또한 나중에 모델 도면층에서 코드를 변경해야 하는 경우에는 뷰 도면층을 변경할 필요가 없습니다.
Django 3.0+의 경우 다음을 사용합니다.models.TextChoices
( 열거형 유형은 docs-v3.0 참조)
from django.db import models
class MyModel(models.Model):
class Month(models.TextChoices):
JAN = "1", "JANUARY"
FEB = "2", "FEBRUARY"
MAR = "3", "MAR"
# (...)
month = models.CharField(
max_length=2,
choices=Month.choices,
default=Month.JAN
)
용도:
>>> obj = MyModel.objects.create(month='1')
>>> assert obj.month == obj.Month.JAN == '1'
>>> assert MyModel.Month(obj.month) is obj.Month.JAN
>>> assert MyModel.Month(obj.month).value is '1'
>>> assert MyModel.Month(obj.month).label == 'JANUARY'
>>> assert MyModel.Month(obj.month).name == 'JAN'
>>> assert MyModel.objects.filter(month=MyModel.Month.JAN).count() >= 1
>>> obj2 = MyModel(month=MyModel.Month.FEB)
>>> assert obj2.get_month_display() == obj2.Month(obj2.month).label
레이블이 'JAN'인 것을 알고 있었다고 가정해 보겠습니다. 'JAN'이라는 이름과 '1'이라는 값을 얻는 방법은 무엇입니까?
label = "JANUARY"
name = {i.label: i.name for i in MyModel.Month}[label]
print(repr(name)) # 'JAN'
value = {i.label: i.value for i in MyModel.Month}[label]
print(repr(value)) # '1'
개인적으로, 저는 차라리models.IntegerChoices
class MyModel(models.Model):
class Month(models.IntegerChoices):
JAN = 1, "JANUARY"
FEB = 2, "FEBRUARY"
MAR = 3, "MAR"
# (...)
month = models.PositiveSmallIntegerField(
choices=Month.choices,
default=Month.JAN
)
설명서에 따르면:
필드.선택사항
이 필드에 대한 선택사항으로 사용할 정확히 두 항목(예: [(A, B), (A, B)...]의 반복 가능한 항목으로 구성된 반복 가능한 항목(예: 목록 또는 튜플)입니다.이 옵션이 지정된 경우 기본 양식 위젯은 표준 텍스트 필드 대신 이러한 선택사항이 있는 선택 상자가 됩니다.
각 튜플의 첫 번째 요소는 저장할 실제 값이고 두 번째 요소는 사람이 읽을 수 있는 이름입니다.
따라서 변수를 정의해야 한다는 점을 제외하고는 코드가 정확합니다.JANUARY
,FEBRUARY
등 또는 사용calendar
정의할 모듈MONTH_CHOICES
:
import calendar
...
class MyModel(models.Model):
...
MONTH_CHOICES = [(str(i), calendar.month_name[i]) for i in range(1,13)]
month = models.CharField(max_length=9, choices=MONTH_CHOICES, default='1')
가장 깨끗한 해결책은 다음을 사용하는 것입니다.django-model-utils
라이브러리:
from model_utils import Choices
class Article(models.Model):
STATUS = Choices('draft', 'published')
status = models.CharField(choices=STATUS, default=STATUS.draft, max_length=20)
https://django-model-utils.readthedocs.io/en/latest/utilities.html#choices
저는 장고 내장 솔루션 대신 장고 모델 유틸리티를 사용할 것을 제안합니다.이 솔루션의 주요 이점은 문자열 선언 중복이 없다는 것입니다.모든 선택 항목이 정확히 한 번 선언됩니다.또한 이것은 3개의 값을 사용하여 선택을 선언하고 소스 코드의 사용과 다른 데이터베이스 값을 저장하는 가장 쉬운 방법입니다.
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
class MyModel(models.Model):
MONTH = Choices(
('JAN', _('January')),
('FEB', _('February')),
('MAR', _('March')),
)
# [..]
month = models.CharField(
max_length=3,
choices=MONTH,
default=MONTH.JAN,
)
대신 IntegerField를 사용하는 경우:
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
class MyModel(models.Model):
MONTH = Choices(
(1, 'JAN', _('January')),
(2, 'FEB', _('February')),
(3, 'MAR', _('March')),
)
# [..]
month = models.PositiveSmallIntegerField(
choices=MONTH,
default=MONTH.JAN,
)
- 이 방법은 IDE에서 한 가지 작은 단점이 있습니다.PyCharm) 사용 가능한 선택 항목에 대한 코드 완성은 없습니다(그 이유는 해당 값이 Choices 클래스의 표준 멤버가 아니기 때문입니다).
2023년 1월 업데이트:
새로운 방법은 모델을 사용하는 것입니다.Text 패키지를 설치할 필요가 없도록 기본 제공되는 아래와 같이 선택합니다.*첫 번째 값은 실제 값이고 두 번째 값은 Django Admin:
# "models.py"
from django.db import models
class MyModel(models.Model):
class Months(models.TextChoices):
# Actual value ↓ # ↓ Displayed on Django Admin
JANUARY = 'JAN', 'January'
FEBRUARY = 'FEB', 'February'
MARCH = 'MAR', 'March'
APRIL = 'APR', 'April'
MAY = 'MAY', 'May'
month = models.CharField(
max_length=3,
choices=Months.choices,
default=Months.APRIL
)
class YearInSchool(models.TextChoices):
# Actual value ↓ # ↓ Displayed on Django Admin
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.SOPHOMORE,
)
또한 위의 코드를 기존의 방식으로 다시 작성하였는데, 이 역시 내장되어 있습니다.
# "models.py"
from django.db import models
class MyModel(models.Model):
# ↓ Actual value
JANUARY = 'JAN'
FEBRUARY = 'FEB'
MARCH = 'MAR'
APRIL = 'APR'
MAY = 'MAY'
MONTHS = [ # ↓ Displayed on Django Admin
(JANUARY, 'January'),
(FEBRUARY, 'February'),
(MARCH, 'March'),
(APRIL, 'April'),
(MAY, 'May'),
]
month = models.CharField(
max_length=3,
choices=MONTHS,
default=APRIL # Or "default=MONTHS[3]"
)
# ↓ Actual value
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
GRADUATE = 'GR'
YEAR_IN_SCHOOL_CHOICES = [
# ↓ Displayed on Django Admin
(FRESHMAN, 'Freshman'),
(SOPHOMORE, 'Sophomore'),
(JUNIOR, 'Junior'),
(SENIOR, 'Senior'),
(GRADUATE, 'Graduate'),
]
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=SOPHOMORE # Or "default=YEAR_IN_SCHOOL_CHOICES[1]"
)
코드에는 맨 단어를 사용할 수 없습니다. 그래서 변수가 생성되었습니다(코드가 실패함).NameError
).
한 코드는 제한코다음이데름이이라는 이름의 데이터베이스 을 생성할 입니다.month
(그리고 접두사 장고가 그것에 추가하는 것은 무엇이든), 왜냐하면 그것이 그 이름이기 때문입니다.CharField
.
하지만 여러분이 원하는 특정한 선택을 할 수 있는 더 나은 방법들이 있습니다.이전 스택 오버플로 문제를 참조하십시오.
import calendar
tuple((m, m) for m in calendar.month_name[1:])
pip 설치된 장고 - 더 좋은 것
관심 있는 사람들을 위해 Python 3.7+의 Django 선택 사항과 함께 작동할 수 있는 멋진 인터페이스를 제공하는 라이브러리를 만들었습니다.사용자 지정 매개 변수, 많은 유용한 기능을 지원하며 IDE에 매우 친숙합니다.
선택 항목을 클래스로 정의할 수 있습니다.
from django_better_choices import Choices
class PAGE_STATUS(Choices):
CREATED = 'Created'
PENDING = Choices.Value('Pending', help_text='This set status to pending')
ON_HOLD = Choices.Value('On Hold', value='custom_on_hold')
VALID = Choices.Subset('CREATED', 'ON_HOLD')
class INTERNAL_STATUS(Choices):
REVIEW = 'On Review'
@classmethod
def get_help_text(cls):
return tuple(
value.help_text
for value in cls.values()
if hasattr(value, 'help_text')
)
그런 다음 다음 작업을 수행하고 훨씬 더 많은 작업을 수행합니다.
print( PAGE_STATUS.CREATED ) # 'created'
print( PAGE_STATUS.ON_HOLD ) # 'custom_on_hold'
print( PAGE_STATUS.PENDING.display ) # 'Pending'
print( PAGE_STATUS.PENDING.help_text ) # 'This set status to pending'
'custom_on_hold' in PAGE_STATUS.VALID # True
PAGE_STATUS.CREATED in PAGE_STATUS.VALID # True
PAGE_STATUS.extract('CREATED', 'ON_HOLD') # ~= PAGE_STATUS.VALID
for value, display in PAGE_STATUS:
print( value, display )
PAGE_STATUS.get_help_text()
PAGE_STATUS.VALID.get_help_text()
그리고 물론 장고 및 장고 마이그레이션이 전적으로 지원합니다.
class Page(models.Model):
status = models.CharField(choices=PAGE_STATUS, default=PAGE_STATUS.CREATED)
전체 설명서는 https://pypi.org/project/django-better-choices/ 에서 확인할 수 있습니다.
언급URL : https://stackoverflow.com/questions/18676156/how-to-properly-use-the-choices-field-option-in-django
'source' 카테고리의 다른 글
iPhone의 NS 문자열에서 HTML 태그 제거 (0) | 2023.06.01 |
---|---|
다른 모델에 정의된 몽구스 데이터베이스의 스키마를 가져오는 방법 (0) | 2023.06.01 |
PostgreSQL: 명령줄에서 매개 변수를 전달하는 방법은 무엇입니까? (0) | 2023.06.01 |
pg_dump를 사용하여 데이터베이스 내의 한 테이블에서만 삽입문 가져오기 (0) | 2023.06.01 |
큰따옴표 대 작은따옴표 (0) | 2023.06.01 |