2009-12-06 5 views
36

Я сделал приятную форму и большую сложную функцию «добавить» для ее обработки. Она начинается, как это ...Django изменить форму на основе формы добавления?

def add(req): 
    if req.method == 'POST': 
     form = ArticleForm(req.POST) 
     if form.is_valid(): 
      article = form.save(commit=False) 
      article.author = req.user 
      # more processing ... 

Теперь я действительно не хочу, чтобы дублировать всю эту функциональность в методе edit(), поэтому я решил edit может использовать один и тот же шаблон, и, возможно, просто добавьте id поле в форма, поэтому функция add знала, что она редактирует. Но есть пара проблем с этим

  1. Где бы я поставил article.id в add FUNC? Это должно быть после form.save, потому что именно там создается статья, но она даже не дойдет до нее, потому что форма недействительна из-за уникальных ограничений (если пользователь не отредактировал все). Я могу просто удалить is_valid чек, но тогда вместо form.save.
  2. Если форма фактически is недействительна, поле, которое я динамически добавляю в функцию редактирования, не сохраняется.

Так как я могу с этим справиться?

ответ

88

Если вы расширяете свою форму от ModelForm, используйте аргумент instance ключевое слово. Здесь мы передаем либо существующий instance, либо новый, в зависимости от того, редактируем ли мы или добавляем существующую статью. В обоих случаях поле author установлено на экземпляре, поэтому commit=False не требуется. Также обратите внимание, что я предполагаю, что автор может редактировать свои статьи, следовательно, HttpResponseForbidden ответ.

from django.http import HttpResponseForbidden 
from django.shortcuts import get_object_or_404, redirect, render, reverse 


@login_required 
def edit(request, id=None, template_name='article_edit_template.html'): 
    if id: 
     article = get_object_or_404(Article, pk=id) 
     if article.author != request.user: 
      return HttpResponseForbidden() 
    else: 
     article = Article(author=request.user) 

    form = ArticleForm(request.POST or None, instance=article) 
    if request.POST and form.is_valid(): 
     form.save() 

     # Save was successful, so redirect to another page 
     redirect_url = reverse(article_save_success) 
     return redirect(redirect_url) 

    return render(request, template_name, { 
     'form': form 
    }) 

и в вашем urls.py:

(r'^article/new/$', views.edit, {}, 'article_new'), 
(r'^article/edit/(?P<id>\d+)/$', views.edit, {}, 'article_edit'), 

То же edit вид используется как для добавления и редактирования, но только шаблон редактирования URL передает идентификатор к виду. Для того, чтобы сделать эту работу хорошо с вашей формой вам нужно опустить author поля из формы:

class ArticleForm(forms.ModelForm): 
    class Meta: 
     model = Article 
     exclude = ('author',) 
+0

Да, это 'ModelForm'. Мне понадобилось «commit = False» по другим причинам. Статья состоит из целого ряда материалов (включая некоторые отношения m2m). Я не думаю, что он хотел работать с «экземпляром». Однако я попробую попробовать. – mpen

+1

В этом случае я бы предложил поместить отношения m2m (et al) сохранение/проверку в форме вместо представления ... либо переопределить метод сохранения, либо, возможно, изучить формы. Я думаю, это зависит от контекста того, с чем вы работаете ... –

+5

Отличный и тщательный пример! Благодаря! Я узнал больше, чем просто решение этого вопроса. – hobbes3

1

У вас может быть скрытое поле идентификатора в форме и для формы редактирования оно будет передано с формой для добавления формы, которую вы можете установить в req.POST, например.

formData = req.POST.copy() 
formData['id'] = getNewID() 

и передать FormData сформировать

Смежные вопросы