Написание пользовательских полей шаблона ¶
Введение ¶
Справочная документация по моделям объясняет, как использовать стандартные поля Django классов: CharField
и DateField
т. Д. В большинстве случаев этих занятий достаточно. Однако могут быть случаи, когда предложение Django не соответствует всем вашим требованиям или вы хотите использовать совершенно другое поле, чем те, которые предоставляет Django.
Встроенные типы полей Django не поддерживают все возможные типы столбцов базы данных, только самые распространенные, такие как VARCHAR
и INTEGER
. Для менее распространенных типов столбцов, таких как географические многоугольники или даже определяемые пользователем типы в стиле пользовательских типов PostgreSQL , вы можете определить свои собственные подклассы Field
.
С другой стороны, у вас может быть сложный объект Python, который можно каким-то образом сериализовать в стандартный тип столбца базы данных. Это еще одна ситуация, когда подкласс Field
может помочь вам использовать этот объект с вашими моделями.
Наш пример объекта ¶
Создание настраиваемых полей требует небольшого внимания к деталям. Чтобы упростить понимание, мы будем использовать единственный пример в этом документе: упаковка объекта Python, представляющего раздачу карт в руке Bridge . Не волнуйтесь, вам не нужно знать, как играть в Bridge, чтобы следовать этому примеру. Просто знайте, что 52 карты равномерно распределены между четырьмя игроками, которые традиционно называются север , восток , юг и запад . Наш класс выглядит так:
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) ...
Это обычный класс Python без специфики Django. Мы хотели бы иметь возможность делать подобные вещи в наших моделях (при условии, что атрибут 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()
Мы пишем и читаем атрибуты hand
нашей модели, как и любой другой класс Python. Хитрость заключается в том, чтобы указать Django, как сохранять и загружать такой объект.
Чтобы иметь возможность использовать класс Hand
в наших моделях, мы не должны каким-либо образом изменять этот класс. Это идеально, потому что это означает, что можно легко реализовать функциональные возможности «шаблона» для существующих классов, исходный код которых нельзя изменить.
Заметка
Возможно, вы захотите воспользоваться преимуществами настраиваемых типов столбцов базы данных и обрабатывать данные в своих моделях, как стандартные типы Python; строки или числа, например, запятые. Эта ситуация аналогична нашему примеру, Hand
и мы укажем на любые различия, когда они появятся.
Теоретические основы ¶
Хранилище базы данных ¶
Начнем с полей шаблона. Вкратце, поле модели - это способ обработать обычный объект Python (строка, логическое значение, один datetime
или несколько сложных объектов, например Hand
) и преобразовать его в формат, подходящий для использования с базой данных. data (этот формат также подходит для сериализации, но позже мы увидим, что это задумано вполне естественно, когда будет освоена часть базы данных).
В любом случае поля шаблона необходимо преобразовать, чтобы они соответствовали типу столбца в базе данных. Различные базы данных предоставляют разные варианты допустимых типов столбцов, но правило всегда одно: это типы, с которыми вам нужно работать. Все, что вы хотите сохранить в базе данных, должно быть одного из этих типов.
Обычно вы либо пишете поле Django, которое будет соответствовать определенному типу столбца базы данных, либо вам нужно найти способ преобразовать ваши данные, например, в строку.
В нашем примере Hand
мы могли бы преобразовать данные карты в строку из 104 символов, объединив все карты в заранее определенном порядке, например сначала все карты севера , затем все карты востока , юга и запада . Таким образом, объекты Hand
могут быть сохранены в текстовых или символьных столбцах базы данных.
Что делает полевой класс? ¶
Все поля Django (и когда мы говорим о полях в этом документе, мы по-прежнему говорим о полях шаблона , а не о полях форм ) являются подклассами django.db.models.Field
. Большая часть информации, которую Django хранит о поле, является общей для всех полей (имя, текст справки, уникальность и т. Д.). Хранением всей этой информации управляет Field
. Мы увидим более точно, что можно сделать Field
чуть позже; а пока давайте просто узнаем, что все наследует Field
и персонализирует ключевые элементы поведения класса.
Важно понимать, что класс поля Django - это не то, что хранится в атрибутах ваших моделей. Атрибуты модели содержат общие объекты Python. Классы полей, которые вы определяете в модели, фактически сохраняются в классе Meta
при создании класса модели (здесь не важно знать точные детали этого процесса). Это связано с тем, что классы полей не нужны, поскольку это просто вопрос создания и изменения атрибутов. С другой стороны, они предоставляют механизмы преобразования между значениями атрибутов и тем, что фактически хранится в базе данных или отправляется в сериализатор .
Помните об этом при создании собственных настраиваемых полей. Подкласс Field
Django, который вы пишете, предоставляет механизмы для преобразования ваших экземпляров Python в значения базы данных или сериализации различными способами (например, существуют различия между сохранением значения и его использованием в запросе. ). Если все это звучит немного сложно, не волнуйтесь, это станет понятнее в приведенных ниже примерах. Просто помните, что вы часто будете создавать два класса, когда хотите создать настраиваемое поле:
- Первый класс - это объект Python, которым будут управлять ваши пользователи. Они будут использовать его как атрибут модели, будут читать его значения для отображения и так далее. Это класс
Hand
в нашем примере. - Второй класс - это подкласс
Field
. Это класс, который знает, как преобразовать ваш первый класс из его полезной формы для хранения в форму Python и наоборот.
Написание подкласса поля ¶
Планируя свой подкласс Field
, сначала подумайте о том, какой из Field
существующих классов ваше новое поле выглядит больше всего. Можно ли наследовать существующее поле Django и сохранить некоторую работу? Если нет, вам придется наследовать от класса, Field
который является родительским для всех остальных.
Инициализация новой области состоит в выделении какого - либо параметра , который является специфическим для своей области, от стандартных параметров, и передавая последний метод __init__()
из Field
(или другого родительского класса).
В нашем примере мы будем называть наше поле HandField
(желательно называть ваш подкласс Field
модели, <QuelqueChose>Field
чтобы мы могли быстро определить, что это подкласс Field
). Наше поле не похоже ни на одно другое существующее поле, поэтому мы наследуем напрямую от 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
и auto_now
к , django.db.models.DateField
и он будет игнорировать параметр editable
(определение» auto_now
означает , что „ редактируемые = False“). В этом случае ошибки не возникает.
Такое поведение упрощает классы полей, поскольку им не нужно проверять ненужные параметры. Они передают все параметры родительскому классу и больше не используют их. Вы должны быть более строгими в отношении принятых параметров или принять более разрешительное поведение текущих полей.
Метод Field.__init__()
принимает следующие параметры:
verbose_name
name
primary_key
max_length
unique
blank
null
db_index
rel
: используется для привязки полей (напримерForeignKey
). Только для продвинутого использования.default
editable
serialize
: даFalse
, поле не будет сериализовано при передаче модели сериализаторам Django. По умолчанию этоTrue
.unique_for_date
unique_for_month
unique_for_year
choices
help_text
db_column
db_tablespace
: только для создания индексов, пока движок управляет табличными пространствами . Обычно эту опцию можно игнорировать.auto_created
: допустимо,True
если элемент управления был создан автоматически, как для элемента управления,OneToOneField
используемого в контексте наследования модели. Только для расширенного использования.
Все параметры без объяснения в приведенном выше списке имеют то же значение, что и для обычных полей Django. См. Полевую документацию для примеров и подробностей.
Деконструкция поля ¶
Аналогом записи метода является запись метода . Это используется во время : docs: `миграции модели </ themes / migrations>`, чтобы сообщить Django, как взять экземпляр нового поля, чтобы сжать его до сериализованного формата; в частности, выбор параметров, которые нужно передать для его воссоздания.__init __()
deconstruct()
__init __()
Если вы не добавили никаких дополнительных параметров в унаследованное вами поле, нет необходимости писать новый метод deconstruct()
. Если, однако, вы измените параметры, переданные в __init__()
(как мы это сделали с HandField
), необходимо будет завершить переданные значения.
deconstruct()
возвращает кортеж из четырех элементов: имя атрибута поля, полный путь импорта класса поля, позиционные параметры (в виде списка) и именованные параметры (в виде словаря). Обратите внимание на разницу с помощью метода deconstruct()
из пользовательского класса , который возвращает кортеж из трех элементов.
Как автору настраиваемого поля вам не нужно беспокоиться о первых двух значениях; базовый класс Field
содержит весь код для определения имени атрибута и пути импорта для поля. Однако вам следует позаботиться о позиционных и именованных параметрах, поскольку они обычно являются частью того, что вы меняете.
Например, в нашем классе HandField
мы всегда принудительно используем max_length
in __init__()
. Метод deconstruct()
базового класса Field
увидит его и попытается вернуть его в названных параметрах; таким образом, мы можем удалить его из именованных параметров для лучшей читаемости:
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
Если вы добавляете новый именованный параметр, вы должны сами написать код, deconstruct()
который помещает его значение в kwargs
. Вам также следует опустить значение, kwargs
когда нет необходимости восстанавливать состояние поля, например, когда используется значение по умолчанию.
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):
...
Как обсуждалось в разделе « Удаление полей» , вам следует сохранять CustomCharField
исходный класс, пока вы сохраняете любые миграции, которые на него ссылаются.
Документация по настраиваемым полям ¶
Как всегда, рекомендуется задокументировать тип поля, чтобы пользователи знали, что это такое. Помимо предоставления ему полезной строки «docstring» для разработчиков, вы также можете разрешить пользователям административного приложения просматривать краткое описание типа поля через приложение django.contrib.admindocs . Для этого укажите описательный текст в атрибуте class description
настраиваемого поля. В приведенном выше примере описанием, отображаемым приложением admindocs
для a, HandField
будет «Карточная рука (стиль моста)».
На дисплее django.contrib.admindocs
описание поля интерполируется с помощью field.__dict__
, что позволяет описанию содержать параметры поля. Например, описание CharField
:
description = _("String (up to %(max_length)s)")
Полезные методы ¶
После создания подкласса Field
может оказаться полезным переопределить некоторые стандартные методы в зависимости от поведения поля. Список методов ниже более или менее расположен в порядке убывания важности, поэтому вам нужно начать с первых.
Пользовательские типы баз данных ¶
Допустим, вы создали собственный тип под названием PostgreSQL mytype
. Вы можете получить 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()
Если ваша цель - создать приложение, не зависящее от выбора базы данных, вы должны знать о различиях в типах столбцов базы данных. Например, в PostgreSQL вызывается столбец типа дата / время, timestamp
а в MySQL - тот же столбец datetime
. Вы можете справиться с этим в методе, db_type()
основанном на атрибуте connection.settings_dict['ENGINE']
.
Например :
class MyDateField(models.Field):
def db_type(self, connection):
if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
return 'datetime'
else:
return 'timestamp'
db_type()
И методы rel_db_type()
называются Джанго , когда система строит инструкции для вашего приложения - то есть, когда таблицы сначала создается. Они также вызываются при создании предложения, которое включает поле шаблона, то есть когда вы извлекаете данные с помощью методов QuerySet, таких как , или, а поле шаблона - найдено в параметре. Они не вызываются в другое время, поэтому они могут позволить себе запускать несколько сложный код, как проверка в приведенном выше примере.CREATE TABLE
WHERE
get()
filter()
exclude()
connection.settings_dict
Некоторые типы столбцов базы данных принимают такие параметры, как 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()
Лучший способ решить эту проблему - разрешить установку параметра во время выполнения, то есть, когда создается экземпляр класса. Для этого реализуйте метод Field.__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, вернитесь None
из
db_type()
. Это приведет к тому, что код создания SQL Django пропустит это поле. Затем вы отвечаете за создание столбца в правой таблице каким-либо другим способом, но это дает вам способ сказать Django, чтобы он не мешал.
Метод rel_db_type()
вызывается такими полями, как ForeignKey
и, OneToOneField
которые указывают на другое поле для определения их типа столбца базы данных. Например, если он у вас есть UnsignedAutoField
, вам также понадобятся внешние ключи, указывающие на это поле, чтобы использовать тот же тип данных:
# 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'
Преобразование значений в объекты Python ¶
Если ваш Field
настраиваемый класс обрабатывает более сложные структуры данных, чем строки, даты, целые числа или числа с плавающей запятой, вам может потребоваться переопределить from_db_value()
и to_python()
.
Если присутствует в подклассе поля, from_db_value()
будет вызываться всякий раз, когда данные загружаются из базы данных, в том числе при вызовах и вызовах агрегирования values()
.
to_python()
вызывается десериализацией и как часть метода, clean()
используемого из форм.
Как правило, to_python()
должен элегантно обрабатывать все следующие параметры:
- Экземпляр правильного типа (например,
Hand
в модельном случае этого документа). - цепь
None
(если поле позволяетnull=True
)
В нашем классе HandField
мы храним данные с полем VARCHAR в базе данных, поэтому нам нужно иметь возможность обрабатывать строки и значение None
в from_db_value()
. В 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, который мы хотим сохранить в атрибуте модели.
Ведь to_python()
если что-то пойдет не так во время преобразования значения, вы должны создать исключение типа ValidationError
.
Преобразование объектов Python в значения запроса ¶
Поскольку использование базы данных требует двустороннего преобразования, при перегрузке from_db_value()
вам также потребуется перегрузка 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 или CHAR
, вы должны убедиться, что метод всегда возвращает строковый тип. MySQL выполняет гибкие, но непредсказуемые совпадения, когда запросы к этим типам выполняются с целым числом, что может привести к тому, что результаты будут содержать неожиданные объекты. Эта проблема не может возникнуть, если вы постоянно возвращаете строки в .VARCHAR
TEXT
get_prep_value()
get_prep_value()
Преобразование значений запроса в значения базы данных ¶
Определенные типы данных (например, даты) должны быть в определенном формате, прежде чем они могут быть использованы ядром базы данных. get_db_prep_value()
это метод, в котором должны выполняться эти преобразования. Конкретное соединение, которое будет использоваться для запроса, передается в качестве параметра connection
. Это позволяет при необходимости использовать логику преобразования конкретного движка.
Например, Django использует для своего поля следующий метод 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
Если для вашего настраиваемого поля требуется специальное преобразование при сохранении, которое отличается от преобразования, используемого для обычных параметров в запросе, вы можете переопределить get_db_prep_save()
.
Предварительная обработка значений перед сохранением ¶
Если вы хотите предварительно обработать значение непосредственно перед сохранением, вы можете использовать pre_save()
. Например, поле DateTimeField
Django использует этот метод для правильной установки атрибута в случае auto_now
или auto_now_add
.
Если вы переопределите этот метод, вы должны вернуть значение атрибута в конце. Вы также должны обновить атрибут модели, если измените значение, чтобы любой код, имеющий ссылки на модель, всегда видел правильное значение.
Выбор поля формы для поля шаблона ¶
Чтобы настроить используемое поле формы ModelForm
, вы можете переопределить formfield()
.
Класс поля формы может быть определен через form_class
и параметры choices_form_class
; последний используется, если поле содержит список вариантов, в противном случае он form_class
учитывается. Если эти параметры отсутствуют, они используются CharField
или TypedChoiceField
будут использоваться.
Все содержимое словаря kwargs
передается непосредственно в метод __init__()
поля формы. Обычно все, что вам нужно сделать, это установить подходящее значение по умолчанию для параметра form_class
(ou choices_form_class
), а затем делегировать остальное родительскому классу. Возможно, вам потребуется написать настраиваемое поле формы (и даже компонент формы). См. Дополнительную информацию по этой теме в документации по формам .
Продолжая наш текущий пример, мы можем написать метод 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
был импортирован (по умолчанию у него есть собственный компонент). В этом документе подробно не рассматривается написание настраиваемых полей формы.
Эмуляция встроенных типов полей ¶
Если вы создали метод db_type()
, не беспокойтесь об этом get_internal_type()
, он не будет много использоваться. Однако могут быть случаи, когда хранилище вашей базы данных имеет тот же тип, что и другое поле, поэтому вы можете повторно использовать логику из этого поля для создания правильного столбца.
Например :
class HandField(models.Field):
# ...
def get_internal_type(self):
return 'CharField'
Независимо от используемого механизма базы данных это означает, что migrate
и другие команды SQL будут создавать столбец правильного типа для хранения строки.
Если get_internal_type()
возвращает строку, которая не известна Django для используемого движка базы данных - то есть, она не отображается в django.db.backends.<db_name>.base.DatabaseWrapper.data_types
- строка все равно будет использоваться сериализатором, но метод по умолчанию db_type()
вернется None
. Обратитесь к документации, db_type()
чтобы узнать, почему это может быть полезно. Помещение описательной строки в тип поля для сериализации - полезная идея, если вам когда-либо понадобится использовать вывод сериализации где-то еще, за пределами Django.
Преобразование данных поля для сериализации ¶
Чтобы настроить способ сериализации значений с помощью сериализатора, вы можете переопределить value_to_string()
. Вызов value_from_object()
- лучший способ получить значение поля до его сериализации. Например, поскольку поле также HandField
использует строки для хранения своих данных, мы можем повторно использовать существующий код преобразования:
class HandField(models.Field):
# ...
def value_to_string(self, obj):
value = self.value_from_object(obj)
return self.get_prep_value(value)
Несколько общих советов ¶
Написание настраиваемого поля может быть утомительным процессом, особенно если вы выполняете сложные преобразования между вашими типами Python и форматами базы данных и сериализации. Вот несколько советов, которые упростят эти операции:
- Посмотрите на существующие поля Django (in
django/db/models/fields/__init__.py
) для вдохновения. Найдите поле, которое выглядит как то, что вы хотите сделать, и заполните то, что вам не хватает, вместо того, чтобы создавать новое поле с нуля. - Напишите метод
__str__()
для класса поля, который вы пишете. Во многих случаях код поля по умолчанию вызываетstr()
значение (в примерах в этом документеvalue
это будет экземплярHand
, а не экземплярHandField
). Итак, если ваш метод__str__()
автоматически преобразует объект Python в текстовую форму, вы сэкономите много работы.
Написание подкласса ¶
В дополнение к указанным выше методам поля, управляющие файлами, должны соответствовать нескольким дополнительным требованиям, которые необходимо учитывать. Большинство предоставляемых механизмов FileField
, таких как овладение хранением в базе данных и извлечением данных, можно оставить как есть; поэтому у подклассов не всегда тривиальная задача - иметь дело с поддержкой определенного типа файла.
Django предоставляет класс, который File
используется в качестве посредника и отвечает за содержание файлов и их операции. Он может быть основой подклассов, которые могут настраивать доступ к файлам и доступные методы. Он расположен в, django.db.models.fields.files
и его поведение по умолчанию объясняется в документации к файлу .
Когда подкласс File
создан, это включает указание новому подклассу того, FileField
что он должен его использовать. Для этого определите новый подкласс File
в специальном атрибуте attr_class
подкласса FileField
.
Некоторые предложения ¶
В дополнение к приведенным выше деталям, вот несколько рекомендаций, которые могут значительно повысить эффективность и читаемость кода поля.
- Исходный код
ImageField
поля Django (indjango/db/models/fields/files.py
) является отличным примером того, как подклассFileField
может поддерживать определенный тип файла, поскольку он учитывает все методы, описанные выше. - Если возможно, кешируйте атрибуты файла. Поскольку файлы могут храниться в удаленных системах, доступ к ним может потребовать временных или даже финансовых затрат, что не всегда необходимо. Как только файл извлекается для получения определенной информации о его содержимом, кэшируйте как можно больше этих данных, чтобы уменьшить количество совпадений файлов, которые могут произойти при возможных будущих запросах той же информации.