11
\$\begingroup\$

Here is the skeleton of my (first!) Django app:

# models.py
class Task(models.Model):
    description = models.CharField(max_length = 200)
    ...

# forms.py
class AddTaskForm(forms.ModelForm):
    class Meta:
        model = Task

I then created two views using AddTaskForm: one to create a new instance, the other to edit an existing one. I was able to refactor those two views (and the function they call) into one, but I'm not sure I got the best possible result...

# urls.py:
(r'^yata/add_task/$',              'yata.views.edit'),
(r'^yata/(?P<task_id>\d+)/edit/$', 'yata.views.edit'),

# views.py
def edit(request, task_id = None):
    t = get_object_or_404(Task, pk=task_id) if task_id else None
    if request.method == 'POST':
        form = AddTaskForm(request.POST, instance=t)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/yata/')
    else:
        form = AddTaskForm(instance = t)

    # Either the form was not valid, or we've just created it
    d = {'form': form}
    if task_id:
        # The template needs the id to decide if the form's action
        # is .../add_task or .../{{id}}/edit
        d['id'] = t.id
    return render_to_response('yata/edit.html', d, 
        context_instance=RequestContext(request))

And here is the corresponding part of the template:

# edit.html
{% if id %}
    <form action="/yata/{{ id }}/edit/" method="post">
{% else %}
    <form action="/yata/add_task/" method="post">
{% endif %}
{{ form.as_p }}
<input type="submit" value="Save!" />
</form>

Is there a better Django idiom to handle this 'add or create' issue? Or can this be considered a correct way?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

I have looked at your code and I think that it actually looks pretty clean and straight forward. However, I would suggest that you make it more DRY by using reverse() to figure out what action to assign to the form.

views.py:

if task_id:
    action = reverse(edit, args=[task_id])
else:
    action = reverse(edit)
d['action'] = action

edit.html:

<form action="{{ action }}" method="post">
    {{ form.as_p }}
    <input type="submit" value="Save!" />
</form>
\$\endgroup\$
1
  • \$\begingroup\$ And, additionally, it helps separating concerns: the view is not supposed to contain the application's logic... Great! Thanks. \$\endgroup\$ Commented Jan 29, 2011 at 7:52
2
\$\begingroup\$

You don't need set "action" for form directly.

# views.py
def edit(request, task_id = None):
    t = get_object_or_404(Task, pk=task_id) if task_id else None

    form = AddTaskForm(request.POST or None, instance=t)
    if form.is_valid():
        form.save()
        return HttpResponseRedirect('/yata/')

    return render_to_response('yata/edit.html', {'form': form}, 
        context_instance=RequestContext(request))

# edit.html
<form action="" method="post">
    {{ form.as_p }}
    <input type="submit" value="Save!" />
</form>
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.