Детальная настройка полей формы
Последнее обновление: 25.02.2018
Форма и поля допускают установку ряда параметров, которые позволяют частично кастомизировать отображение полей и формы. Тем не менее этого нередко бывает недостаточно.
Например, необходимо применить стилизацию или добавить рядом с полем ввода какой-нибудь специальный текст. И Django позволяет нам коренным образом изменить всю композицию создаваемых полей.
В частности, в шаблоне компонента мы можем обратиться к каждому отдельному полю формы через название формы: . По названию поля
мы можем получить непосредственно генерируемый им элемент-html без внешних надписей и какого-то дополнительного кода.
Кроме того, каждое поле имеет ряд ассоциированных с ним значений:
-
: возвращает название поля
-
: возвращает значение поля, которое ему было передано по умолчанию
-
: возвращает текст метки, которая генерируется рядом с полем
-
: возвращает id для поля, которое по умолчанию создается по схеме id_имяполя.
-
: возвращает id для поля, которое по умолчанию создается по схеме id_имяполя.
-
: возвращает элемент label, который представляет метку рядом с полем
-
: возвращает текст подказки, ассоциированный с полем
-
: возвращает ошибки валидации, связанные с полем
-
: возвращает css-классы поля
-
: генерирует для поля разметку в виде скрытого поля
-
: возвращает True или False в зависимости от того, является ли поле скрытым
-
: генерирует для поля разметку в виде текстового поля
-
: генерирует для поля разметку в виде
-
: возвращает виджет Django, ассоциированны с полем
Так, чтобы получить текст на метке поля, которое называется age, нам надо использовать выражение .
Например, возмьмем простейшую форму:
from django import forms class UserForm(forms.Form): name = forms.CharField() age = forms.IntegerField()
В представлении передадим эут форму в шаблон:
from django.shortcuts import render from django.http import HttpResponse from .forms import UserForm def index(request): userform = UserForm() if request.method == "POST": userform = UserForm(request.POST) if userform.is_valid(): name = userform.cleaned_data return HttpResponse("<h2>Hello, {0}</h2>".format(name)) return render(request, "index.html", {"form": userform})
И в шаблоне index.html пропишем использование полей формы:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Django Forms</title> </head> <body> <form method="POST" novalidate> {% csrf_token %} <div> {% for field in form %} <div class="form-group"> `field`.`label_tag` <div>`field`</div> <div class="error">`field`.`errors`</div> </div> {% endfor %} </div> <input type="submit" value="Send" > </form> </body> </html>
Фактически форма представляет набор полей, и с помощью выражения мы пробегаемся по каждому полю на форме и можем управлять его отображением — отображением собственно поля и
связанных с ним атрибутов — ошибок, текста подсказки, метки и т.д.
Например, после отправки некорректных данных мы получим следующую веб-страницу:
Одно поле может содержать несколько ошибок. В этом случае можно использовать тег for для их последовательного вывода:
{% for error in field.errors %} <div class="alert alert-danger">`error`</div> {% endfor %}
НазадВперед
Остальные методы модели¶
Несколько методов имеют специальное назначение.
- ()
Метод вызывается когда вы применяете функцию к объекту. Django использует в нескольких местах. В частности, для отображения объектов в интерфейсе администратора Django и в качестве значения, вставляемого в шаблон, при отображении объекта. Поэтому, вы должны всегда возвращать в методе красивое и удобное для восприятия представление объекта.
Например:
from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # only if you need to support Python 2 class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def __str__(self): return '%s%s' % (self.first_name, self.last_name)
Если вам необходима совместимость с Python 2, Можете декорировать ваш класс модели декоратором .
- ()
Метод проверки равенства по умолчанию работает следующим образом: если два объекта содержат одинаковый первичный ключ и являются экземплярами одно класса, тогда они равны. Для прокси-моделей класс определяется поиском первого не прокси родительского класса. Для всех остальных моделей — это просто класс модели.
Например:
from django.db import models class MyModel(models.Model): id = models.AutoField(primary_key=True) class MyProxyModel(MyModel): class Meta proxy = True class MultitableInherited(MyModel): pass MyModel(id=1) == MyModel(id=1) MyModel(id=1) == MyProxyModel(id=1) MyModel(id=1) != MultitableInherited(id=1) MyModel(id=1) != MyModel(id=2)
- ()
Метод использует значение первичного ключа. На самом деле выполняется . Если первичный ключ не определен, будет вызвано исключение (иначе разные значения перед и после сохранения объекта, что ).
Проектирование моделей LocalLibrary
Перед тем, как вы начнёте программировать модели, стоит потратить несколько минут, чтобы подумать о том, какие данные нам нужно хранить, и о взаимоотношениях между разными объектами.
Мы знаем, что нам нужно хранить информацию о книгах (название, резюме, автор, язык, на котором написана книга, категория, ISBN) и что у нас может быть несколько доступных экземпляров (с уникальным глобальным идентификатором, статусом доступности и т. Д.). Нам может потребоваться хранить больше информации об авторе, чем просто их имя, и могут быть несколько авторов с одинаковыми или похожими именами. Мы хотим иметь возможность сортировать информацию на основе названия книги, автора, письменного языка и категории.
При проектировании ваших моделей имеет смысл иметь отдельные модели для каждого «объекта» (группа связанной информации). В этом случае очевидными объектами являются книги, экземпляры книг и авторы.
Вы также можете использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жёсткого кодирования выбора на самом веб-сайте — это рекомендуется, когда все варианты неизвестны заранее или могут измениться. Очевидные кандидаты на модели в этом случае включают жанр книги (например, «Научная фантастика», «Французская поэзия» и т. д.) И язык (английский, французский, японский).
Как только мы определились с нашими моделями и полями, нам нужно подумать об отношениях. Django позволяет вам определять отношения, как один к одному (), один ко многим () и многие ко многим ().
Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status — мы жёстко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.
На диаграмме также показаны зависимости между моделями, включая их множители. Множители представляют собой числа на диаграмме, показывающие минимум и максимум единиц каждой модели, которые могут присутствовать в этой связи. Например, соединительная линия между ящиками показывает, что книга и жанр связаны между собой. Цифры, близкие к модели жанра, показывают, что у книги может быть один или несколько жанров (сколько угодно), а числа на другом конце строки рядом с моделью книги показывают, что у жанра может быть ноль или более связанных книг.
Примечание. В следующем разделе приведён базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше.
HiddenField¶
Класс поля, которое не принимает значение на основе пользовательского ввода, а берет его из значения по умолчанию или вызываемого поля.
Подпись :
Например, чтобы включить поле, которое всегда предоставляет текущее время как часть проверяемых сериализатором данных, вы можете использовать следующее:
modified = serializers.HiddenField(default=timezone.now)
Класс обычно нужен только в том случае, если у вас есть валидация, которая должна выполняться на основе некоторых предварительно предоставленных значений полей, но вы не хотите раскрывать все эти поля конечному пользователю.
Наследование сериализатора¶
Подобно формам Django, вы можете расширять и повторно использовать сериализаторы с помощью наследования. Это позволяет вам объявить общий набор полей или методов в родительском классе, который затем может быть использован в нескольких сериализаторах. Например,
class MyBaseSerializer(Serializer): my_field = serializers.CharField() def validate_my_field(self, value): ... class MySerializer(MyBaseSerializer): ...
Как и классы Django и , внутренний класс в сериализаторах не наследуется неявно от внутренних классов своих родителей . Если вы хотите, чтобы класс наследовался от родительского класса, вы должны сделать это явно. Например:
class AccountSerializer(MyBaseSerializer): class Meta(MyBaseSerializer.Meta): model = Account
Обычно мы рекомендуем не использовать наследование для внутренних классов Meta, а вместо этого объявлять все опции явно.
Кроме того, следующие предостережения относятся к наследованию сериализаторов:
Другие методы экземпляра модели¶
Несколько методов объекта имеют специальные цели.
- ()
Метод вызывается всякий раз, когда вы вызываете для объекта. Django использует в нескольких местах. В частности, для отображения объекта на сайте администратора Django и в качестве значения, вставляемого в шаблон при отображении объекта. Таким образом, вы всегда должны возвращать хорошее, удобочитаемое представление модели из метода .
Например:
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def __str__(self): return '%s %s' % (self.first_name, self.last_name)
- ()
Метод равенства определен так, что экземпляры с одинаковым значением первичного ключа и одним и тем же конкретным классом считаются равными, за исключением того, что экземпляры со значением первичного ключа не равны ничему, кроме самих себя. Для прокси-моделей конкретный класс определяется как первый непрокси-родитель модели; для всех остальных моделей это просто класс модели.
Например:
from django.db import models class MyModel(models.Model): id = models.AutoField(primary_key=True) class MyProxyModel(MyModel): class Meta proxy = True class MultitableInherited(MyModel): pass # Primary keys compared MyModel(id=1) == MyModel(id=1) MyModel(id=1) != MyModel(id=2) # Primary keys are None MyModel(id=None) != MyModel(id=None) # Same instance instance = MyModel(id=None) instance == instance # Proxy model MyModel(id=1) == MyProxyModel(id=1) # Multi-table inheritance MyModel(id=1) != MultitableInherited(id=1)
- ()
Метод основан на значении первичного ключа экземпляра. Это эффективно . Если у экземпляра нет значения первичного ключа, то будет вызвано (в противном случае метод будет возвращать разные значения до и после сохранения экземпляра, но изменяя значение экземпляра запрещено в Python.
Форма редактирования
Теперь мы знаем, как добавить новую форму. Но что, если мы хотим внести исправления в уже существующую запись? По сути это схожая с предыдущей задача. Давай быстро создадим пару важных вещей (если ты чего-то не понимаешь, спроси своего тренера или загляни в предыдущие главы, поскольку мы уже объясняли все необходимые шаги).
Открой и добавь следующую строку:
blog/templates/blog/post_detail.html
так, чтобы шаблон выглядел следующим образом:
blog/templates/blog/post_detail.html
В файле добавь:
blog/urls.py
Мы будем использовать повторно шаблон , так что осталось лишь отсутствующее представление.
Давай откроем файл и добавим в самый конец следующее:
blog/views.py
Выглядит практически идентично представлению , верно? Но не совсем. Во-первых, мы передаём параметр из URL-адреса. Кроме того, мы получаем модель для редактирования при помощи и передаём экземпляр post в качестве форме и при сохранении…
blog/views.py
… и когда мы открываем форму для редактирования:
blog/views.py
Хорошо, давай удостоверимся, что всё работает! Перейди на страницу . Ты должна увидеть кнопку редактирования в правом верхнем углу:
Когда ты её нажмёшь, то увидишь форму с выбранной записью:
Поменяй заголовок и текст, а затем сохрани запись!
Поздравляем! Твое приложение становится всё более сложным!
Если тебе нужно больше информации о формах в Django, обратись к официальной документации: https://docs.djangoproject.com/en/2.0/topics/forms/
Валидация¶
При десериализации данных всегда нужно вызывать перед попыткой получить доступ к проверенным данным или сохранить экземпляр объекта. Если возникнут ошибки валидации, свойство будет содержать словарь, представляющий сообщения об ошибках. Например:
serializer = CommentSerializer(data={'email' 'foobar', 'content' 'baz'}) serializer.is_valid() # False serializer.errors # {'email': , 'created': }
Каждый ключ в словаре будет именем поля, а значения будут списками строк любых сообщений об ошибках, соответствующих этому полю. Также может присутствовать ключ , который будет перечислять любые общие ошибки валидации. Имя ключа может быть настроено с помощью параметра REST framework.
При десериализации списка элементов ошибки будут возвращены в виде списка словарей, представляющих каждый из десериализованных элементов.
Возникновение исключения при недопустимых данных
Метод принимает необязательный флаг , который заставит его поднять исключение , если есть ошибки валидации.
Эти исключения автоматически обрабатываются обработчиком исключений по умолчанию, который предоставляет фреймворк REST, и по умолчанию возвращают ответы .
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
Валидация на полевом уровне
Вы можете задать пользовательскую валидацию на уровне полей, добавив методы в ваш подкласс . Они аналогичны методам в формах Django.
Эти методы принимают единственный аргумент, который является значением поля, требующего проверки.
Ваши методы должны возвращать подтвержденное значение или вызывать ошибку . Например:
from rest_framework import serializers class BlogPostSerializer(serializers.Serializer): title = serializers.CharField(max_length=100) content = serializers.CharField() def validate_title(self, value): """ Check that the blog post is about Django. """ if 'django' not in value.lower(): raise serializers.ValidationError("Blog post is not about Django") return value
Примечание: Если ваше объявлено в вашем сериализаторе с параметром , то этот шаг проверки не будет выполняться, если поле не включено.
Валидация на уровне объекта
Чтобы выполнить любую другую проверку, требующую доступа к нескольким полям, добавьте метод под названием в ваш подкласс . Этот метод принимает единственный аргумент, который является словарем значений полей. При необходимости он должен вызывать сигнал или просто возвращать проверенные значения. Например:
from rest_framework import serializers class EventSerializer(serializers.Serializer): description = serializers.CharField(max_length=100) start = serializers.DateTimeField() finish = serializers.DateTimeField() def validate(self, data): """ Check that start is before finish. """ if data'start' > data'finish']: raise serializers.ValidationError("finish must occur after start") return data
Документация Django библиотек
Рецепты Django ORM
Рецепты Django ORM — это книга о работе с моделями Django ORM и Django. Django ORM является одним из ключевых столпов Django. Он предоставляет абстракции …
Django Rest Framework
Django Rest Framework (DRF) — это библиотека, которая работает со стандартными моделями Django для создания гибкого и мощного API для проекта.
Django CMS
Django CMS — это современная платформа для веб-публикаций, построенная на Django, фреймворке веб-приложений «для перфекционистов с соблюдением сроков». Django CMS предлагает готовую поддержку общих функций, …
Channels
Channels — это проект, который использует Django и расширяет его возможности за пределы HTTP — для обработки WebSockets, протоколов чата, IoT-протоколов и многого другого. Он …
ASGI — спецификация и утилиты
ASGI (Asynchronous Server Gateway Interface) является духовным наследником WSGI, предназначенным для обеспечения стандартного интерфейса между асинхронными веб-серверами, платформами и приложениями Python. WSGI предоставил стандарт для …
Python Social Auth
Python Social Auth — это простой в настройке механизм социальной аутентификации/регистрации с поддержкой нескольких платформ и провайдеров аутентификации. Созданный с использованием базового кода из django-social-auth, …
Удаление объектов¶
- (using=DEFAULT_DB_ALIAS, keep_parents=False)
Выполняет SQL запрос для объекта. Удаляет объекты только из базы данных; объекты Python будут существовать и содержать данные. Метод возвращает количество удаленных объектов и словарь, который содержит количество удаленных объектов для каждой модели.
Подробности, включая как удалить множество объектов, смотрите в .
Если вам нужно изменить процесс удаления, переопределите метод . Подробности в .
В некоторых случаях при вам может понадобиться удалить только данные дочерней модели. Передав аргумент , вы сохраните данные родительской модели.
Изменено в Django 1.9:
Был добавлен аргумент .
Указание того, какие поля следует включить¶
Если вы хотите, чтобы в сериализаторе модели использовалось только подмножество полей по умолчанию, вы можете сделать это с помощью опций или , так же как и с помощью . Настоятельно рекомендуется явно задать все поля, которые должны быть сериализованы, с помощью атрибута . Это уменьшит вероятность непреднамеренного раскрытия данных при изменении ваших моделей.
Например:
class AccountSerializer(serializers.ModelSerializer): class Meta model = Account fields = 'id', 'account_name', 'users', 'created'
Вы также можете установить атрибут в специальное значение , чтобы указать, что все поля в модели должны быть использованы.
Например:
class AccountSerializer(serializers.ModelSerializer): class Meta model = Account fields = '__all__'
Вы можете установить атрибут в список полей, которые должны быть исключены из сериализатора.
Например:
class AccountSerializer(serializers.ModelSerializer): class Meta model = Account exclude = 'users'
В приведенном выше примере, если модель имела 3 поля , , и , это приведет к тому, что поля и будут сериализованы.
Имена в атрибутах и обычно отображаются на поля модели в классе модели.
Альтернативные имена в опциях могут указывать на свойства или методы, не принимающие аргументов, которые существуют в классе модели.
Документация Django библиотек
Рецепты Django ORM
Рецепты Django ORM — это книга о работе с моделями Django ORM и Django. Django ORM является одним из ключевых столпов Django. Он предоставляет абстракции …
Django Rest Framework
Django Rest Framework (DRF) — это библиотека, которая работает со стандартными моделями Django для создания гибкого и мощного API для проекта.
Django CMS
Django CMS — это современная платформа для веб-публикаций, построенная на Django, фреймворке веб-приложений «для перфекционистов с соблюдением сроков». Django CMS предлагает готовую поддержку общих функций, …
Channels
Channels — это проект, который использует Django и расширяет его возможности за пределы HTTP — для обработки WebSockets, протоколов чата, IoT-протоколов и многого другого. Он …
ASGI — спецификация и утилиты
ASGI (Asynchronous Server Gateway Interface) является духовным наследником WSGI, предназначенным для обеспечения стандартного интерфейса между асинхронными веб-серверами, платформами и приложениями Python. WSGI предоставил стандарт для …
Python Social Auth
Python Social Auth — это простой в настройке механизм социальной аутентификации/регистрации с поддержкой нескольких платформ и провайдеров аутентификации. Созданный с использованием базового кода из django-social-auth, …
Начало
В этом репозитории Github вы найдете основной, функциональный проект с простой реализацией каждого из трех вариантов. Ссылки на соответствующие файлы для каждой опции внутри репо приведены ниже для удобства пользования. В каждый из них я включил отдельный проект и приложение для каждой опции, все с рабочим шаблоном для аутентификации фронтенда, а также с рабочим методом создания суперпользователя, который можно запустить в командной строке.
Все примеры используют Django 1.11 и Python 3.5.2. Каждый из них добавляет поле в модель как , чтобы упростить его, и в первых двух вариантах я делаю поле электронной почты именем пользователя.
Здесь я хотел бы сделать паузу и сказать, что если вы не использовали Django, я рекомендую пройти один или оба превосходных урока от DjangoGirls или Django Docs, чтобы ознакомиться с фреймворком, прежде чем пытаться следовать этому посту. Если вы работали с Django, вы, вероятно, знакомы с моделью , готовой функцией, которую вы можете использовать для аутентификации пользователей (например, создавать учетные записи и входить и выходить из приложения) через класс Python, который представляет таблицу в базе данных и поставляется со множеством встроенных полей и методов для извлечения данных и разрешений, о которых вы можете прочитать в официальной документации.
Указание полей, доступных только для чтения¶
Возможно, вы захотите указать несколько полей как доступные только для чтения. Вместо явного добавления каждого поля с помощью атрибута , вы можете использовать сокращенную опцию Meta, .
Этот параметр должен представлять собой список или кортеж имен полей и объявляется следующим образом:
class AccountSerializer(serializers.ModelSerializer): class Meta model = Account fields = 'id', 'account_name', 'users', 'created' read_only_fields = 'account_name'
Поля модели, для которых установлено , и поля по умолчанию будут установлены в режим «только для чтения», и их не нужно добавлять к опции .
Примечание: Существует особый случай, когда поле, доступное только для чтения, является частью ограничения на уровне модели. В этом случае поле требуется классу сериализатора для проверки ограничения, но также не должно редактироваться пользователем.
Правильным способом решения этой проблемы является явное указание поля в сериализаторе, предоставляя аргументы ключевого слова и .
Одним из примеров этого является отношение только для чтения к текущему аутентифицированному , который является с другим идентификатором. В этом случае вы бы объявили поле user следующим образом:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
ChoiceField¶
Поле, которое может принимать значение из ограниченного набора вариантов.
Используется для автоматической генерации полей, если соответствующее поле модели включает аргумент .
Подпись:
-
— Список допустимых значений, или список кортежей .
-
— Если установлено значение , то пустая строка должна считаться допустимым значением. Если установлено значение , то пустая строка будет считаться недопустимой и вызовет ошибку валидации. По умолчанию установлено значение .
-
— Если установлено, это будет максимальное количество вариантов выбора, которое будет отображаться в выпадающем списке HTML select. Может использоваться для того, чтобы автоматически генерируемые поля выбора с очень большим количеством возможных вариантов выбора не препятствовали отрисовке шаблона. По умолчанию установлено значение .
-
— Если установлено, то будет отображаться текстовый индикатор, если максимальное количество элементов было отсечено в выпадающем списке HTML select. По умолчанию
Работа с вложенными объектами¶
Предыдущие примеры хорошо подходят для работы с объектами, которые имеют только простые типы данных, но иногда нам также необходимо иметь возможность представлять более сложные объекты, где некоторые атрибуты объекта могут быть не простыми типами данных, такими как строки, даты или целые числа.
Класс сам является типом , и может быть использован для представления отношений, где один тип объекта вложен в другой.
class UserSerializer(serializers.Serializer): email = serializers.EmailField() username = serializers.CharField(max_length=100) class CommentSerializer(serializers.Serializer): user = UserSerializer() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
Если вложенное представление может опционально принимать значение , вы должны передать флаг в сериализатор вложенного представления.
class CommentSerializer(serializers.Serializer): user = UserSerializer(required=False) # May be an anonymous user. content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
Аналогично, если вложенное представление должно быть списком элементов, необходимо передать флаг в сериализатор вложенного представления.
Документация Django
Django (Джанго) — свободный фреймворк для веб-приложений на языке Python, использующий шаблон проектирования MVC. Проект поддерживается организацией Django Software Foundation.
Сайт на Django строится из одного или нескольких приложений, которые рекомендуется делать отчуждаемыми и подключаемыми. Это одно из существенных архитектурных отличий этого фреймворка от некоторых других (например, Ruby on Rails). Один из основных принципов фреймворка — DRY (англ. Don’t repeat yourself).
Также, в отличие от других фреймворков, обработчики URL в Django конфигурируются явно при помощи регулярных выражений.
Для работы с базой данных Django использует собственный ORM, в котором модель данных описывается классами Python, и по ней генерируется схема базы данных.
DateTimeField¶
Представление даты и времени.
Соответствует .
Подпись:
-
— Строка, представляющая формат вывода. Если она не указана, то по умолчанию имеет то же значение, что и ключ настроек , который будет , если не установлен. Установка в строку формата указывает на то, что возвращаемые значения должны быть принудительно выведены в строку. Форматные строки описаны ниже. Установка этого значения в указывает, что объекты Python должны быть возвращены . В этом случае кодировка времени суток будет определяться рендерером.
-
— Список строк, представляющих входные форматы, которые могут быть использованы для разбора даты. Если не указано, то будет использоваться параметр , который по умолчанию равен .
-
— , представляющий часовой пояс. Если не указано и включен параметр , то по умолчанию используется current timezone. Если параметр отключен, то объекты datetime будут наивными.
Строки формата могут быть либо Python strftime formats, которые явно указывают формат, либо специальная строка , которая указывает на то, что следует использовать время даты в стиле ISO 8601. (например, )
При использовании значения для формата объекты будут возвращены , а окончательное представление вывода будет определяться классом рендерера.
При использовании или или будут использовать поля сериализатора, которые по умолчанию .
Если вы хотите отменить это поведение, вам нужно будет явно объявить в сериализаторе. Например: