How to create custom model fields¶
도입¶
:doc:’model reference’ 설명서는 Django의 표준 필드 클래스 –:class:’~django.db.db.know.CharField’, :class:’~django.db.db.know.날짜 필드’ 등 여러 가지 목적으로, 그 수업들이 여러분에게 필요한 전부입니다. 하지만 때로는 Django 버전이 사용자의 정확한 요구 사항을 충족하지 못하거나 Django와 함께 제공된 필드와는 완전히 다른 필드를 사용하고자 할 수 있습니다.
django의 내장형 필드에는 “VARCHAR”과 “INTER”와 같은 일반적인 유형의 데이터베이스 열만 포함하지는 않으며 지리적 다각형이나 사용자가 만든 포스트그레그 등 사용자가 만든 열 유형도 포함된다.SQL custom type은 _ __ 사용자 고유의 “Field” 하위 클래스를 정의할 수 있다.
또한, 표준 데이터베이스 열 유형에 맞게 직렬화할 수 있는 복잡한 Python 개체가 있을 수 있습니다. 이것은 ``필드” 서브클래스가 당신의 객체를 당신의 모델과 함께 사용하는 데 도움을 줄 또 다른 경우이다.
우리의 예제 객체¶
사용자 지정 필드를 만들려면 세부 정보에 약간 주의를 기울여야 합니다. 이 문서에서는 Bridge_의 손에서 카드 거래를 나타내는 Python 개체를 감싸는 일관된 예를 보여드리겠습니다. 걱정하지 마세요, 이 예를 따르기 위해 브리지 게임을 하는 방법을 알 필요는 없어요. 52장의 카드가 전통적으로 north, east, south 및 *west*라고 불리는 네 명의 플레이어에 동일하게 배포된다는 것만 알면 됩니다. 저희 클래스는 다음과 같습니다.
class Hand:
"""A hand of cards (bridge style)"""
def __init__(self, north, east, south, west):
# Input parameters are lists of cards ('Ah', '9s', etc.)
self.north = north
self.east = east
self.south = south
self.west = west
# ... (other possibly useful methods omitted) ...
이것은 Django 특유의 것이 없는 평범한 Python 클래스이다. 우리는 우리의 모델에서 이와 같은 것을 할 수 있기를 원한다(우리는 모델의 “hand” 속성은 “hand”의 예라고 가정한다.):
example = MyModel.objects.get(pk=1)
print(example.hand.north)
new_hand = Hand(north, east, south, west)
example.hand = new_hand
example.save()
“우리는 다른 파이썬 클래스처럼 우리 모델의 “손” 속성에 할당하고 이를 조회한다. 요령은 Django에게 그러한 객체를 저장하고 적재하는 방법을 알려주는 것이다.
모델에서 “Hand” 클래스를 사용하기 위해서는 이 클래스를 전혀 변경할 필요가 없다. 소스 코드를 변경할 수 없는 기존 클래스에 대한 모델 지원을 쉽게 작성할 수 있으므로 이상적입니다.
참고
사용자 지정 데이터베이스 열 유형을 활용하고 데이터를 모델에서 표준 Python 유형으로 처리(예: 문자열 또는 부동)하는 것이 좋습니다. 이번 사건은 우리의 ``Hand” 사례와 유사하며 우리는 진행하면서 어떤 차이도 주목하게 될 것이다.
배경설¶
데이터베이스 저장¶
먼저 모델 필드부터 살펴보겠습니다. 이를 세분화하면 모델 필드는 문자열, 부울, “datetime” 또는 “hand”와 같은 일반적인 Python 개체를 가져와서 데이터베이스를 처리할 때 유용한 형식으로 변환하거나 변환하는 방법을 제공한다. (이러한 형식은 직렬화에도 유용하지만 나중에 볼 수 있듯이 데이터베이스를 제어하면 더 쉽습니다.)
모델의 필드는 기존 데이터베이스 열 유형에 맞게 변환되어야 합니다. 데이터베이스마다 서로 다른 유효한 열 유형 집합을 제공하지만 규칙은 여전히 동일합니다. 즉, 이러한 유형만 사용해야 합니다. 데이터베이스에 저장할 항목은 해당 유형 중 하나에 포함되어야 합니다.
일반적으로 특정 데이터베이스 열 유형과 일치하는 Django 필드를 작성하거나 데이터를 문자열로 변환하는 방법이 필요합니다.
우리의 “Hand” 예에서는 모든 카드를 미리 정해진 순서대로 연결함으로써 104자 문자열로 카드 데이터를 변환할 수 있습니다. 예를 들어 모든 북 카드, 그 다음 동, 남 및 서 카드). 따라서 “Hand” 개체를 데이터베이스의 텍스트 또는 문자 열에 저장할 수 있습니다.
필드클래스가 무엇을 하나요?¶
Django의 모든 필드(그리고 이 문서에서 *fields*라고 말할 때, 우리는 항상 모델 필드를 의미하며 :doc:’form fields’가 아님)는 :class:’django.db.models의 하위 클래스이다. Django가 필드에 대해 기록하는 대부분의 정보는 이름, 도움말 텍스트, 고유성 등 모든 필드에 공통적입니다. 그 모든 정보를 저장하는 일은 ``Field`”가 담당한다. 우리는 ``Field`”가 나중에 무엇을 할 수 있는지 자세히 알아볼 것이다. 현재로서는 모든 것이 ``Field`”에서 비롯되었다고 말하고 나서 계급 행동의 핵심 부분을 맞춤화한다고만 말해도 충분하다.
Django 필드 클래스는 모델 속성에 저장된 클래스가 아닙니다. 모델 속성은 일반 Python 개체를 포함합니다. 사용자가 모델에 정의한 필드 클래스는 모델 클래스가 생성될 때 “메타” 클래스에 저장됩니다(여기서는 자세한 작업 내용이 중요하지 않음). 그 이유는 속성을 만들고 수정할 때는 필드 클래스가 필요하지 않기 때문입니다. 대신, 그들은 속성 값과 데이터베이스에 저장되거나 :doc:’serializer’로 전송되는 것 사이에서 변환하는 기계를 제공한다.
사용자 정의 필드를 작성할 때 이 점을 유념하십시오. 작성하는 Django “Field” 하위 클래스는 다양한 방법으로 Python 인스턴스와 데이터베이스/시리얼라이저 값을 변환하는 기계를 제공합니다(예를 들어 값을 저장하는 것과 룩업에 값을 사용하는 것 사이에는 차이점이 있음). 만약 이것이 좀 까다롭게 들린다면, 걱정하지 마세요. 아래의 예에서 더 명확해질 것입니다. 사용자 지정 필드를 원할 때 두 개의 클래스를 만드는 경우가 많습니다.
- 첫 번째 클래스는 사용자가 조작할 Python 개체입니다. 그들은 그것을 모델 속성에 할당하고, 그것을 보여주기 위해 읽게 될 것입니다. 이것이 우리의 예에서 볼 수 있는 “Hand” 클래스이다.
- 두 번째 클래스는 ``Field” 하위 클래스다. 이 클래스는 퍼스트 클래스를 영구 스토리지 폼과 Python 폼 사이에서 앞뒤로 변환하는 방법을 알고 있는 클래스입니다.
필드상속 작성법¶
클래스 계획 시:’~django.db.db.know.필드의 하위 클래스는 먼저 기존의 :클래스 중 어느 것을 생각하는지 제시합니다.’~django.db.db.know.필드 클래스는 새 필드와 가장 유사합니다. 기존 Django 필드를 하위 분류하여 작업을 저장할 수 있습니까? 그렇지 않으면 모든 것이 내려온 필드의 :class.’~django.db.db.know. 를 하위 분류해야 합니다
. :class’~django.db.db.know.Field(또는 부모 클래스)의 메소드는 당신의 새로운 필드를 초기화하는 것은 당신의 경우에 특정한 어떤 주장과 공통적인 주장을 분리해서 후자를 “__init__()” 방법에 전달하는 문제입니다
In our example, we’ll call our field HandField
. (It’s a good idea to call
your Field
subclass <Something>Field
, so it’s
easily identifiable as a Field
subclass.) It doesn’t
behave like any existing field, so we’ll subclass directly from
Field
:
from django.db import models
class HandField(models.Field):
description = "A hand of cards (bridge style)"
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
super().__init__(*args, **kwargs)
우리의 “HandField”는 대부분의 표준 필드 옵션(아래 목록 참조)을 수용하지만 52개의 카드 값과 그 정장, 총 104자만 보유하면 되기 때문에 길이가 고정되어 있음을 보장한다.
참고
Django의 모델 분야 중 많은 부분은 그들이 아무것도 하지 않는 옵션을 받아들인다. 예를 들어, editable
and auto_now
두 가지를 모두 django.db.models.DateField
로 전달 할 수 있고 auto_now
being set implies editable=False
). 를 무시한다.
이 동작은 필요하지 않은 옵션을 확인할 필요가 없으므로 필드 클래스를 단순화합니다. 모든 옵션을 부모 클래스에 전달한 다음 나중에 사용하지 않습니다. 선택한 옵션에 대해 필드를 더 엄격하게 지정하거나 현재 필드의 더 관대한 동작을 사용할지 여부는 사용자에게 달려 있습니다.
‘’`Field.__init__()’ 방법은 다음과 같은 파라미터를 사용합니다.
verbose_name
name
primary_key
max_length
unique
blank
null
db_index
rel
: Used for related fields (likeForeignKey
). 고급 사용시default
editable
- “serialize”: “False”이라면, 모델이 장고 :doc :”serializers”에 전달될 때 그 분야는직렬화되지 않을 것이다. 기본값은 “TRUE”입니다.
unique_for_date
unique_for_month
unique_for_year
choices
help_text
db_column
db_tablespace
: 백엔드에서 :doc:’tablespaces’를 지원하는 경우에만 인덱스 생성에 사용됩니다. 일반적으로 이 옵션을 무시할 수 있습니다.- 필드가 자동으로 생성된 경우,:class:~django.db.models.OneToOneField 가 모델 상속으로 사용된 경우,
auto_created
: ``True``이다. 고급 사용시
위의 목록에 설명이 없는 모든 옵션은 일반 D장고 필드에 대해 동일한 의미를 가집니다. 예시와 자세한 내용은 :doc:’field documentation’를 참조하십시오.
필드 해체¶
당신의 ``__init__()” 방식을 쓰는 것의 대척점은 :meth:”를 쓰는 것이다.Field.deconstruction’ 메서드입니다. 그것은 :doc:’model migration’에서 Django에게 당신의 새로운 필드의 예를 들어 그것을 직렬화된 형태로 줄이는 방법, 특히 그것을 재생성하기 위해 “_init_()”로 전달할 인수들을 말한다.
물려받은 분야 위에 별도의 옵션을 추가하지 않았다면 굳이 새로운 ```deconstruct()” 방식을 쓸 필요가 없다. 그러나 만일 당신이 ``_init__()” (우리가 “HandField”에 있는 것처럼)로 전달된 주장을 바꾼다면, 당신은 통과되는 값을 보완할 필요가 있을 것이다.
deconstruct()" 는 4개의 아이템의 튜플을 반환합니다 :필드 속성 이름, 필드 클래스의 전체 가져오기 경로, 위치 인수(목록으로) 및 키워드 인수(dict로)가 있습니다. 이는 3개의 튜플을 반환하는 ``deconstruct()
method :ref:` 과는 다릅니다.
사용자 지정 필드 작성자로서 기본 ``Field” 클래스는 필드의 속성 이름과 가져오기 경로를 결정하는 모든 코드를 가지고 있기 때문에 앞의 두 값에 신경 쓸 필요가 없습니다. 그러나 위치 및 키워드 인수에 주의해야 합니다. 이러한 인수는 사용자가 변경하는 것일 수 있기 때문입니다.
예를 들어 우리의 ``HandField” 클래스에서 우리는 항상 max_length를 ``__init__()”로 강제적으로 설정한다. “Field” 클래스의 ``deconstruct() “방식은 이것을 보고 키워드 논쟁에서 반환하려고 할 것이다. 따라서 우리는 이것을 가독성을 위한 키워드 논쟁에서 빼놓을 수 있다.
from django.db import models
class HandField(models.Field):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
del kwargs["max_length"]
return name, path, args, kwargs
새로운 키워드 논거를 추가하면 그 가치를 스스로 “kwags”에 넣는 ``decorruction()”이라는 코드를 쓸 필요가 있다. 기본값이 사용되는 경우와 같이 필드 상태를 재구성할 필요가 없는 경우 “kwags”에서 값을 생략해야 한다.
from django.db import models
class CommaSepField(models.Field):
"Implements comma-separated storage of lists"
def __init__(self, separator=",", *args, **kwargs):
self.separator = separator
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
# Only include kwarg if it's not the default
if self.separator != ",":
kwargs['separator'] = self.separator
return name, path, args, kwargs
좀 더 복잡한 예는 이 문서의 범위를 벗어나지만 기억하라. 즉, 필드 인스턴스의 구성에 대해서는 “`deconstruct()”가 해당 상태를 재구성하기 위해 “_init__”로 전달할 수 있는 인수를 반환해야 한다.
“Field” 슈퍼클래스의 인수에 대해 새로운 기본값을 설정하는 경우 특히 주의를 기울이십시오. 인수가 이전 기본값을 사용하는 경우 인수가 사라지더라도 항상 포함되도록 하려는 경우입니다.
또한 값을 위치 인수로 반환하지 않도록 하십시오. 가능한 경우 값을 키워드 인수로 반환하여 미래의 호환성을 최대화합니다. 생성자의 인수 목록에서 위치보다 항목의 이름을 더 자주 변경할 경우 위치 지정을 선호할 수 있지만 마이그레이션 기간(년)에 따라 사람들이 직렬화된 버전에서 사용자 필드를 오랫동안 재구성할 수 있습니다.
필드를 포함하는 마이그레이션을 확인하여 재구성 결과를 확인할 수 있으며, 필드를 재구성하고 재구성하여 단위 테스트에서 재구성을 테스트할 수 있습니다.
name, path, args, kwargs = my_field_instance.deconstruct()
new_instance = MyField(*args, **kwargs)
self.assertEqual(my_field_instance.some_attribute, new_instance.some_attribute)
사용자 맞춤 정의 필드의 기본 클래스 변경¶
Django가 변경 내용을 검색하지 않고 해당 필드에 대해 마이그레이션을 수행하므로 사용자 정의 필드의 기본 클래스를 변경할 수 없습니다. 예를 들어, 다음 항목으로 시작하는 경우:
class CustomCharField(models.CharField):
...
대신 “TextField”를 사용하기로 결정하면 다음과 같이 하위 클래스를 변경할 수 없습니다.
class CustomCharField(models.TextField):
...
대신 새 사용자 지정 필드 클래스를 만들고 모델을 업데이트하여 참조해야 합니다.
class CustomCharField(models.CharField):
...
class CustomTextField(models.TextField):
...
“ref:’moving fields’에서 논했듯이, 당신은 그것을 참조하는 마이그레이션이 있는 한 원래의 “Custom CharField” 클래스를 보유해야 한다.
사용자 맞춤 정의 필드 문서화¶
사용자가 필드 유형을 알 수 있도록 항상 필드 유형을 문서화해야 합니다. 개발자에게 유용한 docstring을 제공할 뿐만 아니라 admin 앱의 사용자가 :doc:’django.contrib.admindocs’ 애플리케이션을 통해 필드 유형에 대한 간단한 설명을 볼 수 있도록 할 수 있습니다. 이렇게 하려면 사용자 정의 필드의 :attr:’~Field.description’ 클래스 속성에 설명 텍스트를 입력합니다. 위의 예에서 ``핸드필드”를 신청하는 ``애드민더스”가 보여주는 묘사는 카드의 손(브리지 스타일)이 될 것이다.
:mod:’django.contrib.admindocs’ 디스플레이에서 필드 설명은 “field”로 보간된다.__dict__’’는 필드 인수를 포함할 수 있는 설명입니다. 예를 들어 :class에 대한 설명:’~django.db.db.know.CharField’는 다음과 같다.
description = _("String (up to %(max_length)s)")
쓸모있는 메소드들¶
:class를 생성했으면:’~django.db.db.know.필드의 하위 클래스는 필드 동작에 따라 몇 가지 표준 방법을 재정의하는 것을 고려할 수 있습니다. 아래 방법 목록은 중요도가 대략적으로 감소하는 순서이므로 맨 위에서부터 시작하십시오.
사용자 맞춤 정의 데이터베이스 유형¶
Postgre를 생성했다고 가정해 보십시오.SQL 사용자 정의 유형은 “my type”입니다. 다음과 같이 “Field”를 하위 분류하고 :meth:’~Field.db_type” 방법을 구현할 수 있습니다.
from django.db import models
class MytypeField(models.Field):
def db_type(self, connection):
return 'mytype'
일단 “MytypeField”를 갖게 되면 다른 “Field” 타입과 마찬가지로 어떤 모델에서도 사용할 수 있다.
class Person(models.Model):
name = models.CharField(max_length=80)
something_else = MytypeField()
If you aim to build a database-agnostic application, you should account for
differences in database column types. For example, the date/time column type
in PostgreSQL is called timestamp
, while the same column in MySQL is called
datetime
. You can handle this in a db_type()
method by
checking the connection.vendor
attribute. Current built-in vendor names
are: sqlite
, postgresql
, mysql
, and oracle
.
예시:
class MyDateField(models.Field):
def db_type(self, connection):
if connection.vendor == 'mysql':
return 'datetime'
else:
return 'timestamp'
:meth:’~Field.db_type’ 및 :meth:’~Field.rel_db_type’ 방법은 프레임워크가 당신의 애플리케이션에 대한 ``CREATE TABLE” 문을 구성할 때 즉, 당신이 당신의 테이블을 처음 만들 때 Django에 의해 호출된다. 이 방법은 모델 필드를 포함하는 ``WHERE” 조항 즉 ``필터()”와 “제외()”와 같은 쿼리셋 방법을 사용하여 데이터를 검색하고 모델 필드를 논쟁으로 삼을 때도 호출된다. 그들은 다른 때 호출되지 않기 때문에 그것은 ``연결”과 같은 약간 복잡한 코드를 실행할 여유가 있다.위의 예에서 settings_laints를 체크합니다.
일부 데이터베이스 열 유형에는 “CHAR(25)”과 같은 매개 변수가 최대 열 길이를 나타내는 “25”와 같은 매개 변수가 허용된다. 이러한 경우 매개변수가 “db_type()” 방식으로 하드 코딩되기 보다는 모델에 지정되면 더 유연하다. 예를 들어 여기에 “CharMaxlength25Field”가 나와 있는 것은 말이 되지 않는다.
# This is a silly example of hard-coded parameters.
class CharMaxlength25Field(models.Field):
def db_type(self, connection):
return 'char(25)'
# In the model:
class MyModel(models.Model):
# ...
my_field = CharMaxlength25Field()
이렇게 하는 더 좋은 방법은 런타임에 매개 변수를 지정할 수 있게 하는 것입니다. 즉, 클래스가 인스턴스화된 경우입니다. 그러기 위해서는 ``필드”를 실행하라.__init__()는 다음과 같습니다.
# This is a much more flexible example.
class BetterCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(*args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
# In the model:
class MyModel(models.Model):
# ...
my_field = BetterCharField(25)
마지막으로, 컬럼에 실제로 복잡한 SQL 설정이 필요한 경우 :meth:”none”에서 “none”을 반환합니다. 이로 인해 Django의 SQL 생성 코드가 이 필드를 건너뜁니다. 그러면 다른 방법으로 오른쪽 테이블에 열을 만들 책임이 있지만, 이것은 여러분이 Django에게 해결방법을 제공합니다.
:meth:’~Field.rel_db_type’은 다른 필드를 가리키는 “ForeignKey”와 “OneToOneField”와 같은 분야로 불리며 데이터베이스 열 데이터 유형을 결정한다. 예를 들어 “미서명”이 있는 경우AutoField’에서 동일한 데이터 유형을 사용하려면 해당 필드를 가리키는 외래 키도 필요합니다.
# MySQL unsigned integer (range 0 to 4294967295).
class UnsignedAutoField(models.AutoField):
def db_type(self, connection):
return 'integer UNSIGNED AUTO_INCREMENT'
def rel_db_type(self, connection):
return 'integer UNSIGNED'
값을 파이썬 개체로 변환¶
사용자 정의:클래스:’~Field’ 클래스는 문자열, 날짜, 정수 또는 부동보다 복잡한 데이터 구조를 다루므로 meth:’~from_db_value’ 및 :meth:’~Field’를 재정의해야 할 수 있습니다.
필드 서브클래스에 “from_db_value()”가 존재하면 aggregate 및 :meth:”~django.db.models.QuerySet.values를 포함하여 데이터베이스에서 데이터가 로드되는 모든 상황에서 호출됩니다.의 호출입니다.
to_python()
는 역직렬화(deserialization)에 의해 호출되고 :meth:`~django.db.models.Model.clean`메소드가 폼 도중에 사용된다.
일반적으로 ``to_python()”은 다음 주장 중 하나를 기품 있게 다루어야 한다.
- 올바른 유형의 예(예: 현재 진행 중인 예에서 “Hand”)
- 문자열
- ``None``(필드에서 “null = True”를 허용한다면)
“HandField`” 클래스에서는 데이터를 데이터베이스에 VARCHAR 필드로 저장하므로 “from_db_value()”에서 문자열과 “`None”을 처리할 수 있어야 한다. ``to_python()”에서 우리는 또한 ```Hand”의 인스턴스를 다룰 필요가 있다.
import re
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
def parse_hand(hand_string):
"""Takes a string of cards and splits into a full hand."""
p1 = re.compile('.{26}')
p2 = re.compile('..')
args = [p2.findall(x) for x in p1.findall(hand_string)]
if len(args) != 4:
raise ValidationError(_("Invalid input for a Hand instance"))
return Hand(*args)
class HandField(models.Field):
# ...
def from_db_value(self, value, expression, connection):
if value is None:
return value
return parse_hand(value)
def to_python(self, value):
if isinstance(value, Hand):
return value
if value is None:
return value
return parse_hand(value)
“우리는 항상 이러한 방법에서 ``Hand”의 예를 되돌려 놓는다는 것을 주목하라. 모델의 속성에 저장하려는 Python 개체 유형입니다.
For to_python()
, if anything goes wrong during value conversion, you should
raise a ValidationError
exception.
파이썬 개체를 질의 값으로 변환하는 중¶
데이터베이스를 사용하려면 두 가지 방식으로 변환해야 하므로 :meth:’~Field.from_value’를 재정의할 경우 :meth:’~Field.get_prep_value’도 재정의해야 Python 개체를 다시 쿼리 값으로 변환할 수 있습니다.
예시:
class HandField(models.Field):
# ...
def get_prep_value(self, value):
return ''.join([''.join(l) for l in (value.north,
value.east, value.south, value.west)])
경고
사용자 지정 필드가 MySQL에 대해 “CAR”, “VARCHAR” 또는 “TEXT” 유형을 사용하는 경우 :meth:methget_prep_value”가 항상 문자열 유형을 반환하는지 확인해야 한다. 이러한 유형에 대해 쿼리가 수행되고 제공된 값이 정수인 경우 MySQL은 유연하고 예상치 못한 일치를 수행하므로 쿼리에 예기치 않은 개체가 결과에 포함될 수 있습니다. 문자열 유형을 항상 :meth:meth:>get_prep_value’에서 반환하는 경우에는 이 문제가 발생할 수 없습니다.
질의 값을 데이터베이스 값으로 변환하는 중¶
일부 데이터 유형(예: 날짜)은 데이터베이스 백엔드에서 사용하려면 특정 형식이어야 합니다. :meth:’~Field.get_db_prep_value’는 이러한 변환을 수행해야 하는 방법입니다. 쿼리에 사용될 구체적인 연결은 “연결” 매개변수로 전달된다. 이렇게 하면 필요한 경우 백엔드별 변환 로직을 사용할 수 있습니다.
예를 들어, Django는 다음 방법을 사용하여 다음을 수행합니다.:class:BinaryField:
def get_db_prep_value(self, value, connection, prepared=False):
value = super().get_db_prep_value(value, connection, prepared)
if value is not None:
return connection.Database.Binary(value)
return value
저장 시 일반 쿼리 파라미터에 사용되는 변환과 다른 특수 변환이 필요한 경우 meth:’~Field.db_prep_save’를 재정의할 수 있습니다.
저장하기 전에 값 사전 처리¶
저장하기 직전에 값을 사전 처리하려는 경우:meth:~Field.pre_save.을 사용할 수 있다. 예를 들어, django 의 auto_now
or auto_now_add
. 의 경우들의 속성을 알맞게 집합한다.
이 메서드를 재정의하는 경우 속성 값을 마지막에 반환해야 합니다. 모델에 대한 코드 유지 참조가 항상 올바른 값을 볼 수 있도록 값을 변경한 경우에도 모델의 속성을 업데이트해야 합니다.
모델필드의 폼필드 명시¶
ModelForm
, 의 사용할 양식 필드를 사용자 정의하려면:meth:~Field.formfield. 오버라이드할수 있다.
양식 필드 클래스는 “form_class”와 “choices_form_class” 인수를 통해 지정할 수 있으며, 필드에는 선택사항이 있는 경우 후자를 사용하고, 그렇지 않은 경우 전자를 사용한다. 이러한 인수가 제공되지 않은 경우 :class:’~django’ 입니다.양식.CharField’ 또는 :class:’~django’ 입니다..TypeedChoiceField’가 사용됩니다.
모든 ``kwags” 사전은 양식장의 ``_init__()” 방식에 직접 전달된다. 보통 당신이 해야 할 일은 ``form_class” (그리고 어쩌면 “choices_form_class”) 논쟁에 대한 좋은 디폴트를 설정한 다음 부모 계층에게 더 많은 처리를 위임하는 것이다. 사용자 정의 양식 필드 및 양식 위젯을 작성해야 할 수 있습니다. 자세한 내용은 :doc:’양식 문서’를 참조하십시오.
계속 예를 들면 :meth:’Field.formfield’ 메소드를 다음과 같이 작성할 수 있습니다.
class HandField(models.Field):
# ...
def formfield(self, **kwargs):
# This is a fairly standard way to set up some defaults
# while letting the caller override them.
defaults = {'form_class': MyFormField}
defaults.update(kwargs)
return super().formfield(**defaults)
이것은 우리가 (기본 위젯이 있는) ``MyFormField” 필드 클래스를 수입했다고 가정한다. 이 문서에서는 사용자 정의 양식 필드 작성에 대한 세부 정보를 다루지 않습니다.
내장된 필드 유형 에뮬레이션¶
:meth:methdb_type’ method를 생성했다면 :meth:meth:malget_internal_type’에 대해 걱정할 필요가 없습니다. 많이 사용되지 않습니다. 그러나 데이터베이스 저장소의 유형이 다른 필드와 비슷할 때도 있으므로 다른 필드의 논리를 사용하여 올바른 열을 만들 수 있습니다
예시:
class HandField(models.Field):
# ...
def get_internal_type(self):
return 'CharField'
어떤 데이터베이스 백엔드를 사용하든, 이것은 :djadmin:’migrate’와 다른 SQL 명령어가 문자열을 저장하기 위한 올바른 열 유형을 생성한다는 것을 의미한다.
:meth :meth:malcget_internal_type’이 사용 중인 데이터베이스 백엔드에 대해 Django에 알 수 없는 문자열을 반환하는 경우 즉, “django.db.backends”에는 나타나지 않습니다.base.DataWrapper.data_types’ – 이 문자열은 직렬화기에서 계속 사용되지만 기본값인 meth:’~Field.db_type’ 메서드는 “없음”을 반환합니다. 유용한 이유는 :meth:’~Field.db_type’ 문서를 참조하십시오. 설명 문자열을 직렬화기의 필드 유형으로 삽입하는 것은 Django 이외의 다른 위치에서 직렬화기 출력을 사용할 경우에 유용합니다.
직렬화를 위한 필드 데이터 변환¶
일련 번호에 의해 값이 직렬화되는 방식을 사용자 정의하기 위해 meth:’~Field.value_to_string’을 재정의할 수 있습니다. :meth:’~Field.value_from_object’를 사용하면 직렬화 전에 필드 값을 얻을 수 있습니다. 예를 들어 “핸드필드”는 어쨌든 데이터 스토리지에 문자열을 사용하기 때문에 다음과 같은 기존 변환 코드를 재사용할 수 있다.
class HandField(models.Field):
# ...
def value_to_string(self, obj):
value = self.value_from_object(obj)
return self.get_prep_value(value)
일반적인 조언¶
특히 Python 유형과 데이터베이스 및 직렬화 형식 간에 복잡한 변환을 수행하는 경우에는 사용자 지정 필드를 작성하는 작업이 까다로울 수 있습니다. 다음은 작업을 보다 원활하게 진행할 수 있도록 하는 몇 가지 팁입니다.
- 기존의 Django 필드(‘django/db/models/fields/__init__py’ 파일)를 보고 영감을 얻습니다. 완전히 새로운 필드를 처음부터 새로 만드는 대신 원하는 필드와 유사한 필드를 찾아서 약간 확장하십시오.
- 필드로 마무리하는 수업에 “__str__()” 방식을 적용합니다. 필드 코드의 기본 동작은 값에 대해 “str()”라고 부르는 경우가 많다. (이 문서의 예에서 “가치”는 ``핸드필드”가 아니라 “손”의 예일 것이다. 그래서 만약 당신의 ``_str__()” 방법이 당신의 파이썬 객체의 문자열 형태로 자동 변환된다면, 당신은 많은 작업을 절약할 수 있다.
``FileField``의 하위 클래스 작성¶
위의 방법 외에도 파일을 처리하는 필드에는 몇 가지 다른 특수한 요구 사항이 고려되어야 합니다. 데이터베이스 저장 및 검색 통제 등 ``파일 필드”가 제공하는 메커니즘의 대다수는 변하지 않을 수 있어 하위 클래스는 특정 유형의 파일을 지원해야 하는 과제를 떠안게 된다.
django는 파일의 내용과 작업을 대신하는 “파일” 클래스를 제공한다. 파일 액세스 방법과 사용 가능한 방법을 사용자 정의하기 위해 하위 분류할 수 있습니다. 그것은 ``django.db.models.fields”에 산다.files는 다음과 같이 처리되며, 기본 동작은 :doc:’file docation’에 설명되어 있다.
일단 “파일”의 서브클래스가 만들어지면 새로운 “파일필드” 서브클래스는 그것을 사용하라는 말을 들어야 한다. 그러기 위해서는 새로운 “파일” 하위 클래스를 “파일 필드” 하위 클래스의 “attr_class” 특성의 “파일” 하위 클래스를 할당해야 한다.
몇 가지 제안들¶
위의 세부 사항 외에도 필드 코드의 효율성과 가독성을 크게 개선할 수 있는 몇 가지 지침이 있습니다.
- Django 자신의 “ImageField”의 출처(“django/db/db/fields/files.py에 있음)는 위에서 설명한 모든 기술을 포함하고 있기 때문에 특정 유형의 파일을 지원하기 위해 “FileField”를 하위 분류하는 방법을 보여주는 좋은 예이다.
- 가능한 경우 파일 특성을 캐시합니다. 파일을 원격 스토리지 시스템에 저장할 수 있기 때문에 파일을 검색하는 데 추가 시간 또는 비용이 소요될 수 있습니다. 항상 필요한 것은 아닙니다. 파일이 검색되어 콘텐츠에 대한 데이터를 얻으면 해당 데이터를 가능한 많이 캐슁하여 이후 해당 정보를 호출할 때 파일을 검색해야 하는 횟수를 줄이십시오.