Создание модели и связанных моделей с помощью встроенных форм - PullRequest
39 голосов
/ 11 июля 2009

[Я разместил это у пользователей Django | Группы Google также.]

Используя пример из встроенных документов формы , я могу редактировать объектов, принадлежащих конкретной модели (используя modelforms). Я пытался следовать той же схеме для создание новых объектов с использованием встроенных наборов форм, но не удалось Очисти мою голову достаточно, чтобы вывести рабочий взгляд для этой цели.

Используя тот же пример, что и в приведенной выше ссылке, как мне поступить создание нового экземпляра модели «Автор» вместе с соответствующими «Книжные» объекты?

Ответы [ 3 ]

36 голосов
/ 02 февраля 2011

Я бы на самом деле хотел предложить небольшую корректировку решения nbv4:

Предположим, что вы не создаете пустого create_author вне оператора if-else и, следовательно, должны вложить formset в author_form.is_valid (), чтобы избежать ошибок времени выполнения, когда author_form недопустим (и, следовательно, не создан проиллюстрированный).

Вместо:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save()
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...

Выполните следующие действия:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save(commit=False)
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            created_author.save()
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...

Эта версия избегает фиксации create_author, пока book_formset не сможет подтвердить. Вариант использования для исправления состоит в том, что кто-то заполняет допустимую AuthorForm недействительным BookFormSet и продолжает повторную отправку, создавая несколько записей Author без книг, связанных с ними. Кажется, это работает для моего приложения для отслеживания проекта (замените «Автор» на «Проект» и «Книга» на «Роль»).

36 голосов
/ 11 июля 2009

Сначала создайте форму модели Author.

author_form = AuthorModelForm()

затем создайте фиктивный объект автора:

author = Author()

Затем создайте встроенный набор форм, используя фиктивного автора следующим образом:

formset = BookFormSet(instance=author)  #since author is empty, this formset will just be empty forms

Отправьте это в шаблон. После того, как данные возвращаются обратно в представление, вы создаете автора:

author = AuthorModelForm(request.POST)
created_author = author.save()  # in practice make sure it's valid first

Теперь подключите встроенный набор форм к вновь созданному автору, а затем сохраните:

formset = BookFormSet(request.POST, instance=created_author)
formset.save()   #again, make sure it's valid first

редактирование:

Чтобы не иметь флажков на новых формах, сделайте это шаблоном:

{% for form in formset.forms %}
    <table>
    {% for field in form %}
        <tr><th>{{field.label_tag}}</th><td>{{field}}{{field.errors}}</td></tr>
    {% endfor %}

    {% if form.pk %} {# empty forms do not have a pk #}
         <tr><th>Delete?</th><td>{{field.DELETE}}</td></tr>
    {% endif %}
    </table>
{% endfor %}
9 голосов
/ 11 июля 2009

models.py (Контакт)

first = models.CharField(max_length=30)
middle = models.CharField('M.I.',max_length=30, blank=True)
last = models.CharField(max_length=30)
sort_order = models.PositiveIntegerField(default=99)

models.py (Ссылка)

class Link(models.Model):
    contact = models.ForeignKey(Contact)
    link = models.URLField()
    description = models.CharField(max_length=30)
    access_date = models.DateField(blank=True,null=True)

forms.py

from django.forms import ModelForm
from contacts.models import Contact

class ContactAjaxForm(ModelForm):
    class Meta:
    model=Contact

views.py

def edit(request,object_id=False):
    LinkFormSet = inlineformset_factory \
           (Contact,Link,extra=1)
    if object_id:
        contact=Contact.objects.get(pk=object_id)
    else:
        contact=Contact()
    if request.method == 'POST':
        f=forms.ContactAjaxForm(request.POST, request.FILES, instance=contact)
        fs = LinkFormSet(request.POST,instance=contact)
        if fs.is_valid() and f.is_valid():
            f.save()
            fs.save()
            return HttpResponse('success')
    else:
        f  = forms.ContactAjaxForm(instance=contact)
        fs = LinkFormSet(instance=contact)
    return render_to_response('contacts/edit.html', \
               {'fs': fs,'f':f,'contact':contact})

Это не основано на примере в книге, оно отредактировано из некоторого кода на моем сайте. Я не проверял это, так что может быть какие-то ошибки, но в целом все должно быть надежно. Использование пустого экземпляра Contact не является рекомендуемым методом, но он экономит немного логики и работает.

Редактировать: добавлена ​​модель связи, переключенная на обычный внешний ключ вместо общего внешнего ключа, что сбивает с толку

...