При разработке приложения, использующего базу данных, чаще всего вы будете работать с формами, которые аналогичны моделям. Например, имея модель BlogComment, вам может потребоваться создать форму, которая позволит людям отправлять комментарии. В этом случае явное определение полей формы будет дублировать код, так как все поля уже описаны в модели.
По этой причине Django предоставляет вспомогательный класс, который позволит вам создать класс Form по имеющейся модели.
Например:
>>> from django.forms import ModelForm
# Create the form class.
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
# Creating a form to add an article.
>>> form = ArticleForm()
# Creating a form to change an existing article.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)
Созданный экземпляр класса Form будет иметь поля для каждого поля модели. Каждому полю модели соответствует стандартное поле формы. Например, CharField поле модели будет представлено на форме как CharField, а ManyToManyField поле модели будет представлено как MultipleChoiceField. Ниже представлен полный список соответствия полей модели и формы:
Поле модели | Поле формы |
---|---|
AutoField | Не представлено на форме |
BigIntegerField | IntegerField с атрибутом min_value равным -9223372036854775808 и атрибутом max_value равным 9223372036854775807. |
BooleanField | BooleanField |
CharField | CharField с атрибутом max_length равным значению атрибута max_length модели |
CommaSeparatedIntegerField | CharField |
DateField | DateField |
DateTimeField | DateTimeField |
DecimalField | DecimalField |
EmailField | EmailField |
FileField | FileField |
FilePathField | CharField |
FloatField | FloatField |
ForeignKey | ModelChoiceField (см. далее) |
ImageField | ImageField |
IntegerField | IntegerField |
IPAddressField | IPAddressField |
GenericIPAddressField | GenericIPAddressField |
ManyToManyField | ModelMultipleChoiceField (см. далее) |
NullBooleanField | CharField |
PhoneNumberField | USPhoneNumberField (из модуля django.contrib.localflavor.us) |
PositiveIntegerField | IntegerField |
PositiveSmallIntegerField | IntegerField |
SlugField | SlugField |
SmallIntegerField | IntegerField |
TextField | CharField с widget=forms.Textarea |
TimeField | TimeField |
URLField | URLField с атрибутом verify_exists равным атрибутом verify_exists поля модели. |
Как вы могли ожидать, ForeignKey и ManyToManyField поля модели являются особыми случаями:
В дополнение, каждое поле созданной формы имеет следующие атрибуты:
В конце, следует отметить, что вы можете переопределить поле формы, используемое для определённого поля модели. Обратитесь к Overriding the default field types or widgets далее.
Рассмотрим этот набор полей:
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
class BookForm(ModelForm):
class Meta:
model = Book
Для этих моделей показанные выше классы ModelForm будут аналогичны следующим формам (разница будет только в методе save(), что мы вскоре рассмотрим.):
from django import forms
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(max_length=3,
widget=forms.Select(choices=TITLE_CHOICES))
birth_date = forms.DateField(required=False)
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
При первом вызове метода is_valid() или обращении к атрибуту errors форма ModelForm выполняет валидацию полученный данных, как это описано в model validation. Побочным эффектом данного действия является очистка модели, которую вы передали в конструктор ModelForm. Например, вызов is_valid() для вашей формы преобразует все поля дат вашей модели в настоящие объекты даты.
Каждая форма, созданная с помощью ModelForm, обладает методом save(). Этот метод создаёт и сохраняет объект в базе данных, используя для этого данные, введённые в форму. Класс, унаследованный от ModelForm может принимать существующий экземпляр модели через именованный аргумент instance. Если такой аргумент указан, то save() обновит переданную модель. В противном случае, save() создаст новый экземпляр указанной модели:
# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)
# Save a new Article object from the form's data.
>>> new_article = f.save()
# Create a form to edit an existing Article.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(instance=a)
>>> f.save()
# Create a form to edit an existing Article, but use
# POST data to populate the form.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()
Следует отметить, что метод save() вызывает исключение ValueError, если данные формы не прошли проверку, т.е. атрибут errors формы вычисляется в True.
Метод save() принимает необязательный именованный аргумент commit, который может иметь значения True или False. Если вы вызовите save() с commit=False, то метод вернёт объект, который ещё не был сохранён в базе данных. В этом случае, вам самостоятельно придётся вызвать метод save() у полученного объекта. Это бывает полезно, когда требуется выполнить дополнительные действия над объектом до его сохранения или если вам требуется воспользоваться одним из параметров сохранения модели. Атрибут commit по умолчанию имеет значение True.
Использование commit=False также полезно в случае, когда ваша модель имеет связь “многие-ко-многим” с другой моделью. Для такой модели, если метод save() вызван с аргументом commit=False, то Django не может немедленно сохранить данные для такой связи. Это происходит так, потому что невозможно создать такую связь для экземпляра, пока он не сохранён в базе данных.
Чтобы решить эту задачу, каждый раз когда вы сохраняете форму, указывая commit=False, Django добавляет метод save_m2m() к вашему классу ModelForm. После того, как вы вручную сохранили экземпляр формы, вы можете вызвать метод save_m2m() для сохранения данных, связанних через “многие-ко-многим”. Например:
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)
# Modify the author in some way.
>>> new_author.some_field = 'some_value'
# Save the new instance.
>>> new_author.save()
# Now, save the many-to-many data for the form.
>>> f.save_m2m()
Вызов метода save_m2m() требуется только в случае, если вы используете save(commit=False). Если вы просто используете save() для формы, то все данные (включая связи “многие-ко-многим”), будут сохранены, не требуя для этого дополнительных действий. Например:
# Create a form instance with POST data.
>>> a = Author()
>>> f = AuthorForm(request.POST, instance=a)
# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()
Если не принимать во внимание методы save() и save_m2m(), то ModelForm работает аналогично обычной Form. Например, метод is_valid() используется для проверки данных, метод is_multipart() используется для определения загрузки файла (в этом случае request.FILES должен быть передан форме) и так далее. Обратитесь к документу Привязка загруженных файлов к форме для получения подробностей.
В некоторых случаях может потребоваться выводить лишь часть полей модели на форме. Существует три способа указать ModelForm, какие именно поля модели надо использовать:
Например, если требуется, чтобы форма для модели Author (определена выше) отображала только поля name и title, укажите атрибуты fields или exclude вот так:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
Так как модель Author содержит всего три поля: name ``title `` и ``birth_date, то вышеприведённые формы будут отображать одни и те же поля.
Примечание
Если вы указываете fields или exclude при создании формы через ModelForm, то поля, которые не определены в форме, не будут учитываться при вызове метода save(). Также, если вы вручную добавите в форму исключенные поля, то они не будут заполняться из экземпляра модели.
Django будет препятствовать всем попыткам сохранить неполную модель. Таким образом, если модель требует заполнения определённых полей и для них не предоставлено значение по умолчанию, то сохранить форму для такой модели не получится. Для решения этой проблемы вам потребуется создать экземпляр такой модели, передав ему начальные значения для обязательных, но незаполненных полей:
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
В качестве альтернативы, вы можете использовать save(commit=False) и вручную определить все необходимые поля:
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Обратитесь к разделу section on saving forms для подробностей по использованию save(commit=False).
Стандартные типы полей, описанные выше, имеют целесообразные настройки по умолчанию. Если ваша модель имеет поля типа DateField, то скорее всего вы пожелаете, чтобы форма использовала поле DateField для его отображения. Но класс ModelForm представляет широкие возможности по управлению типами полей формы, а также виджетами для их представления.
Для того, чтобы указать собственный виджет для поля следует использовать атрибут widgets внутреннего класса Meta. Его значением должен быть словарь, ключами которого являются имена полей, а значениями — классы или экземпляры виджетов.
Например, если необходимо, чтобы поле name модели Author было представлено в виде <textarea> вместо стандартного <input type="text">, то вы можете переопределить виджет поля:
from django.forms import ModelForm, Textarea
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title', 'birth_date')
widgets = {
'name': Textarea(attrs={'cols': 80, 'rows': 20}),
}
Ещё раз напомним, что аргумент widgets принимает словарь с экземплярами (т.е., Textarea(...)) или классами (т.е., Textarea) виджетов.
Если вы желаете продолжить настойку поля, включая его тип, метку и так далее, то вы можете явно указать поля, как это делается при использовании Form. Эти поля переопределят поля модели.
Например, если надо использовать MyDateFormField для поля pub_date, вы можете сделать следующее:
class ArticleForm(ModelForm):
pub_date = MyDateFormField()
class Meta:
model = Article
Если вам требуется изменить стандартную метку у поля, то укажите параметр ``label `` при определении поля формы:
>>> class ArticleForm(ModelForm):
... pub_date = DateField(label='Publication date')
...
... class Meta:
... model = Article
Примечание
При явном создании поля, Django предполагает, что вы будете определять поведение формы в целом. Следовательно, стандартные атрибуты модели (такие как max_length или required) не передаются полям формы. Если вам потребуется обеспечить поведение, определённое в модели, вам потребуется явно установить соответствующие аргументы при определении поля формы.
Например, если модель Article выглядит так:
class Article(models.Model):
headline = models.CharField(max_length=200, null=True, blank=True,
help_text="Use puns liberally")
content = models.TextField()
и вы желаете выполнить свою проверку поля headline, оставляя неизменными атрибуты blank и help_text, вы можете определить ArticleForm следующим образом:
class ArticleForm(ModelForm):
headline = MyFormField(max_length=200, required=False,
help_text="Use puns liberally")
class Meta:
model = Article
Обратитесь к `документации на поля формы`</ref/forms/fields>`_ для получения дополнительной информации о полях и их аргументах.
По умолчанию ModelForm выводит поля в порядке, в котором они определены в модели, добавляя в конец экземпляры ManyToManyField. Если вам потребуется изменить порядок отображения полей, вы можете использовать атрибут fields класса Meta.
Атрибут fields определяет набор полей модели, подлежащих отображению, и их порядок на форме. Например, рассмотрим эту модель:
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
поле author будет выведено первым. Если же надо первым вывести поле title, то определим ModelForm так:
>>> class BookForm(ModelForm):
... class Meta:
... model = Book
... fields = ('title', 'author')
Вы можете переопределить метод clean() модели для того, чтобы обеспечить дополнительную проверку. Всё это аналогично работе с обычной формой.
Учитывая это, модельные формы обладают двумя особенностями по сравнению с формами:
По умолчанию метод clean() проверяет уникальность полей, которые помечены в модели как unique, unique_together или unique_for_date|month|year. Таким образом, если вам потребуется переопределить этот метод, то не забудьте вызвать метод clean() базового класса для проверки уникальности полей.
Экземпляр модельной формы, привязанный к объекту модели имеет атрибут self.instance, через который методы модельной формы имеют доступ к соответствующему экземпляру модели.
Аналогично обычным формам, вы можете наследоваться ModelForm. Это удобно когда надо добавить дополнительные поля или методы к базовому классу и использовать результат для создания других модельных форм. Например, для класса ArticleForm:
>>> class EnhancedArticleForm(ArticleForm):
... def clean_pub_date(self):
... ...
Мы создали форму, аналогичную ArticleForm, добавив дополнительную проверку и обработку для поля pub_date.
Вы также можете наследовать внутренний класс Meta, если требуется внести изменения в списки Meta.fields или Meta.excludes:
>>> class RestrictedArticleForm(EnhancedArticleForm):
... class Meta(ArticleForm.Meta):
... exclude = ('body',)
Здесь мы добавили метод из EnhancedArticleForm и изменили оригинальный ArticleForm.Meta, убрав одно поле.
Тем не менее, надо уточнить несколько моментов.
Скорее всего вы с этим не столкнетесь до тех пор, пока не потребуется сделать что-то хитрое, используя наследование.
В процессе проверки данных ModelForm будет вызывать метод clean() каждого поля вашей модели, соответствующего полю формы. Для полей модели, которые были исключены из формы, проверка данных производиться не будет. Обратитесь к документации по проверке форм для получения информации о том как работает проверка данных поля. Также, метод clean() вашей модели будет вызываются перед каждой проверкой на уникальность. Обратитесь к документации по проверке объектов для получения информации по методу clean() модели.
Аналогично наборам обычных форм, Django представляет ряд расширенных классов наборов форм, которые упрощают взаимодействие с моделями Django. Давайте воспользуемся моделью Author:
>>> from django.forms.models import modelformset_factory
>>> AuthorFormSet = modelformset_factory(Author)
Этот код создаст набор форм, которые будут работать с данными модели Author. По функционалу набор модельных форм аналогичен набору обычных форм:
>>> formset = AuthorFormSet()
>>> print formset
<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
<option value="" selected="selected">---------</option>
<option value="MR">Mr.</option>
<option value="MRS">Mrs.</option>
<option value="MS">Ms.</option>
</select></td></tr>
<tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>
Примечание
Фабрика по созданию модельных форм modelformset_factory использует фабрику обычных форм formset_factory для создания набора форм. Это означает, что функционал модельных форм является надстройкой над функционалом набора обычных форм.
По умолчанию, при создании набора модельных форм используется выборка, которая содержит все объекты модели (т.е., Author.objects.all()). Такое поведение можно скорректировать, используя аргумент queryset:
>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
Также вы можете унаследоваться от класса набора модельных форм и определить self.queryset в конструкторе, указав необходимые параметры выборки:
from django.forms.models import BaseModelFormSet
class BaseAuthorFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
self.queryset = Author.objects.filter(name__startswith='O')
Теперь передадим ваш класс BaseAuthorFormSet в функцию фабрики:
>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
Если требуется создать пустой набор форм, т.е. который не включает ни одну существующую модель, то передайте в набор пустую выборку:
>>> AuthorFormSet(queryset=Author.objects.none())
По умолчанию набор модельных форм использует все поля модели, которые не отмечены как editable=False. Тем не менее, такое поведение может быть изменено на уровне набора форм:
>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
Использование аргумента``fields`` ограничивает набор форм указанным списком полей. В качестве альтернативы можно определить список полей, которые не должны отображаться на формах. Сделать это можно с помощью аргумента exclude:
>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))
Аналогично набору обычных форм, есть возможность указать начальные данные для форм набора, передав параметр initial при создании экземпляра набора, возвращенного modelformset_factory. Тем не менее, в случае набора модельных форм, начальными значениями заполняются только пустые, т.е. новые, формы.
Благодаря ModelForm, вы можете сохранять данные в модели. Для этого надо использовать метод save() набора форм:
# Create a formset instance with POST data.
>>> formset = AuthorFormSet(request.POST)
# Assuming all is valid, save the data.
>>> instances = formset.save()
Метод save() возвращает экземпляры объектов, которые были сохранены в базе данных. Те объекты, данные которых не изменились, не сохраняются в базе данных и не отображаются в возвращаемом значении (instances из предыдущего примера).
Когда форма содержит не все поля модели (например, потому что некоторые из них были явно исключены), то отсутствующие поля не будут сохранены через метод save(). Подробнее об этом ограничении модельных форм написано в Using a subset of fields on the form.
Передайте commit=False, чтобы получить экземпляры моделей, которые ещё не сохранены в базе данных:
# don't save to the database
>>> instances = formset.save(commit=False)
>>> for instance in instances:
... # do something with instance
... instance.save()
Это позволяет вам добавлять данные к экземплярам моделей перед их сохранением в базе данных. Если ваш набор форм содержит ManyToManyField, вам также потребуется вызвать метод formset.save_m2m() для того, чтобы обеспечить сохранение связей «многие-ко-многим».
Как и в случае набора обычных форм, вы можете использовать аргументы max_num и extra функции modelformset_factory для ограничения числа дополнительно отображаемых форм.
Аргумент max_num не препятствует отображению существующих объектов:
>>> Author.objects.order_by('name')
[<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
>>> AuthorFormSet = modelformset_factory(Author, max_num=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> [x.name for x in formset.get_queryset()]
[u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']
Если значение max_num больше чем количество существующих объектов, то к будет добавлено extra пустых форм к набору. Так будет происходить до достижения максимального количества форм, ограниченного параметром max_num:
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> for form in formset:
... print form.as_table()
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
Присвоение max_num значения None (по умолчанию) снимет ограничение на количество отображаемых набором форм.
Наборы модельных форм во многом похожи на наборы обычных форм. Для отображения набора форм для редактирования экземпляров модели Author:
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
if request.method == 'POST':
formset = AuthorFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
# do something.
else:
formset = AuthorFormSet()
return render_to_response("manage_authors.html", {
"formset": formset,
})
Как вы можете видеть, логика представления не сильно отличается отличается логики обычного набора. Отличием является вызов formset.save() для сохранения данных. (Это было описано ранее в Сохранение объектов набора форм.)
Подобно``Forms``, по умолчанию метод clean() набора модельных форм будет проверять все данные на нарушение ограничений уникальности, определённых в вашей модели (unique, unique_together или unique_for_date|month|year). Желая сохранить данный функционал при переопределении метода clean(), следует вызывать метод clean() базового класса:
class MyModelFormSet(BaseModelFormSet):
def clean(self):
super(MyModelFormSet, self).clean()
# example custom validation across forms in the formset:
for form in self.forms:
# your custom formset validation
Как было сказано ранее, в можете переопределить стандартную выборку, которая используется набором модельных форм:
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
if request.method == "POST":
formset = AuthorFormSet(request.POST, request.FILES,
queryset=Author.objects.filter(name__startswith='O'))
if formset.is_valid():
formset.save()
# Do something.
else:
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
return render_to_response("manage_authors.html", {
"formset": formset,
})
Следует отметить, что мы передаём аргумент queryset в обе ветки POST и GET в этом примере.
Существует три способа отображения набора форм в шаблоне Django.
Во-первых, вы можете позволить набору форм самому сделать всю работу:
<form method="post" action="">
{{ formset }}
</form>
Во-вторых, в можете вручную вывести набор форм, но позволить его формам отображаться самостоятельно:
<form method="post" action="">
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
</form>
При самостоятельном отображении форм, не забудьте отобразить техническую форму, как было показано выше. Обратитесь к документации на технические формы.
В-третьих, вы можете вручную выводит все поля:
<form method="post" action="">
{{ formset.management_form }}
{% for form in formset %}
{% for field in form %}
{{ field.label_tag }}: {{ field }}
{% endfor %}
{% endfor %}
</form>
Если вы предпочтёте третий способ и не будете использовать {% for %} для итерации по полям, то вам понадобится вывести поле для первичного ключа. Рассмотрим случай, когда требуется вывести поля name и age модели:
<form method="post" action="">
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
<ul>
<li>{{ form.name }}</li>
<li>{{ form.age }}</li>
</ul>
{% endfor %}
</form>
Обратите внимание на то, как мы явно выводим {{ form.id }}. Это гарантирует, что набор модельных форм, в случае POST, будет работать правильно. (Этот пример предполагает, что первичный ключ имеет имя id. Если вы изменили имя первичного ключа, то учтите это в данном примере.)
Встраиваемые наборы форм являются небольшим абстрактным слоем над набором модельных форм. Они упрощают работу со связанными через внешний ключ объектами. Предположим у вас есть следующие две модели:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
Если вам требуется создать набор форм для редактирования книг принадлежащих определенному автору, вы можете сделать следующее:
>>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book)
>>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet(instance=author)
Примечание
inlineformset_factory использует modelformset_factory и устанавливает can_delete=True.
См.также
Если ваша модель иметь больше одного внешнего ключа на одну и ту же модель, вам следует разрешить эту путаницу, указав fk_name. Например, рассмотрим следующую модель:
class Friendship(models.Model):
from_friend = models.ForeignKey(Friend)
to_friend = models.ForeignKey(Friend)
length_in_months = models.IntegerField()
Чтобы разрешить эту неопределенность, вы может использовать fk_name в inlineformset_factory:
>>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
Вам может понадобиться создать представление, которое позволит пользователю редактировать связанные объекты модели. Вот как это можно сделать:
def manage_books(request, author_id):
author = Author.objects.get(pk=author_id)
BookInlineFormSet = inlineformset_factory(Author, Book)
if request.method == "POST":
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
formset.save()
# Do something.
else:
formset = BookInlineFormSet(instance=author)
return render_to_response("manage_books.html", {
"formset": formset,
})
Следует отметить, что мы передаём instance в обоих (POST и GET) случаях.
Aug 21, 2013