11. Formularios¶
“Django provides a range of tools and libraries to help you build forms to accept input from site visitors, and then process and respond to the input.”
Ahora que la interfaz de inicio de sesión está funcionando, podemos construir el formulario para crear marcadores.
11.1. Add URLs for the forms¶
Primero tienes que extender el URLconf de la aplicación marcador en mysite/marcador/urls.py
con dos nuevos URLs:
1 2 3 4 5 6 7 8 9 10 11 12 | from django.conf.urls import url
urlpatterns = [
url(r'^user/(?P<username>[-\w]+)/$', 'marcador.views.bookmark_user',
name='marcador_bookmark_user'),
url(r'^create/$', 'marcador.views.bookmark_create',
name='marcador_bookmark_create'),
url(r'^edit/(?P<pk>\d+)/$', 'marcador.views.bookmark_edit',
name='marcador_bookmark_edit'),
url(r'^$', 'marcador.views.bookmark_list', name='marcador_bookmark_list'),
]
|
El primero ^create/$
es completamente estático y una la correspondiente vista a la ruta /create/
.
El patrón ^edit/(?<pk>\d+)/$
tiene una parte variable que captura la llave primaria (PK) de el marcador. La llave primaria se añade a todos los modelos por Django, así que cada entrada tiene una identificador único. La ruta /edit/1/
conduce por ejemplo al marcador con la llave primaria 1
.
Entre las partes estáticas edit
al principio /
al final se encuentra el grupo (?P<pk>\d+)
. Con \d+
captura cualquier número de caracteres numéricos y los almacena en la variable pk
que puede ser usada en la vista.
11.2. Add the Form¶
El siguiente paso es crear el formulario. Para crearlo, añade el archivo mysite/marcador/forms.py
:
1 2 3 4 5 6 7 8 9 | from django.forms import ModelForm
from .models import Bookmark
class BookmarkForm(ModelForm):
class Meta:
model = Bookmark
exclude = ('date_created', 'date_updated', 'owner')
|
La clase de formulario BookmarkForm
también se denomina ModelForm porque hereda de django.forms.ModelForm
. Los ModelForms crean automáticamente campos de formulario para cada campo en el modelos al que pertenecen. El enlace de los models se hace en la clase interna Meta
que debe estar presente en cada ModelForm.
For security reasons the value owner
mustn’t be editable through the form
because otherwise it would be possible to foist a bookmark on another user.
Therefore owner
is added to the list of excluded fields. The same is done
with the fields date_created
and date_updated
because they are
set automatically.
11.3. Add the Views¶
Ahora puede crear dos nuevas vistas que usan BookmarkForm
. La primera se usa para crear nuevos marcadores:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404, redirect, render
from .forms import BookmarkForm
from .models import Bookmark
def bookmark_list(request):
bookmarks = Bookmark.public.all()
context = {'bookmarks': bookmarks}
return render(request, 'marcador/bookmark_list.html', context)
def bookmark_user(request, username):
user = get_object_or_404(User, username=username)
if request.user == user:
bookmarks = user.bookmarks.all()
else:
bookmarks = Bookmark.public.filter(owner__username=username)
context = {'bookmarks': bookmarks, 'owner': user}
return render(request, 'marcador/bookmark_user.html', context)
@login_required
def bookmark_create(request):
if request.method == 'POST':
form = BookmarkForm(data=request.POST)
if form.is_valid():
bookmark = form.save(commit=False)
bookmark.owner = request.user
bookmark.save()
form.save_m2m()
return redirect('marcador_bookmark_user',
username=request.user.username)
else:
form = BookmarkForm()
context = {'form': form, 'create': True}
return render(request, 'marcador/form.html', context)
|
El decorador @login_required
se asegura que la vista es sólo accesible a usuarios autenticados. Otros vistantes son re dirigidos a la página de inicio de sesión.
The first step is to check if the request was done via POST. If yes, the form is initialized with the POST data.
The form gets validated by using form.is_valid()
. If the validation was
successful, the new bookmark can be saved with form.save(commit=False)
. The
argument commit=False
prevents the ModelForm from saving the bookmark, it
just returns the model instance prepared with the validated data. Now the
current user is added as the owner and the bookmark is saved. After that
form.save_m2m()
is called to create the relationships to the Tag
models. Finally the user gets redirected to his or her bookmark list.
Si la validación no fue exitosa o si la solicitud fue hecha a través de GET, el formulario se pasa a la plantilla donde se lo puede presentar incluyendo posibles mensajes de error.
Two values are passed to the template as context variables. The dictionary key
form
contains the instance of BookmarkForm
. create
is a boolean
value and is used to determine if the template is used to create or edit a
bookmark because it is used in both views.
La segunda vista permite editar marcadores:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, redirect, render
from .forms import BookmarkForm
from .models import Bookmark
def bookmark_list(request):
bookmarks = Bookmark.public.all()
context = {'bookmarks': bookmarks}
return render(request, 'marcador/bookmark_list.html', context)
def bookmark_user(request, username):
user = get_object_or_404(User, username=username)
if request.user == user:
bookmarks = user.bookmarks.all()
else:
bookmarks = Bookmark.public.filter(owner__username=username)
context = {'bookmarks': bookmarks, 'owner': user}
return render(request, 'marcador/bookmark_user.html', context)
@login_required
def bookmark_create(request):
if request.method == 'POST':
form = BookmarkForm(data=request.POST)
if form.is_valid():
bookmark = form.save(commit=False)
bookmark.owner = request.user
bookmark.save()
form.save_m2m()
return redirect('marcador_bookmark_user',
username=request.user.username)
else:
form = BookmarkForm()
context = {'form': form, 'create': True}
return render(request, 'marcador/form.html', context)
@login_required
def bookmark_edit(request, pk):
bookmark = get_object_or_404(Bookmark, pk=pk)
if bookmark.owner != request.user and not request.user.is_superuser:
raise PermissionDenied
if request.method == 'POST':
form = BookmarkForm(instance=bookmark, data=request.POST)
if form.is_valid():
form.save()
return redirect('marcador_bookmark_user',
username=request.user.username)
else:
form = BookmarkForm(instance=bookmark)
context = {'form': form, 'create': False}
return render(request, 'marcador/form.html', context)
|
Here the primary key pk
is used to fetch the bookmark from the
database. If no bookmark with this PK exists, the HTTP status code 404
is returned. If the current user isn’t the owner (bookmark.owner !=
request.user
) and isn’t a superuser (not
request.user.is_superuser
), access is denied and the HTTP status code
403 is returned.
Aparte de eso, el proceso es similar a bookmark_create
. Pero el formulario es inicializado con la instancia bookmark (instance=bookmark
). De esta manera, todos los campos del formulario son pre-llenados con los valores antiguos. SI los datos POST están presentes, anula los valores de la instancia bookmark.
In addition the key create
in the context dictionary is set to False
because this view is only used to edit existing bookmarks.
11.4. Add the Templates¶
Ahora puedes añadir la plantilla para el formulario mysite/marcador/templates/marcador/form.html
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | {% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}
{% if create %}Create{% else %}Edit{% endif %} bookmark
{% endblock %}
{% block heading %}
<h2>
{% if create %}
Create bookmark
{% else %}
Edit bookmark
{% endif %}
</h2>
{% endblock %}
{% block content %}
{% if create %}
{% url "marcador_bookmark_create" as action_url %}
{% else %}
{% url "marcador_bookmark_edit" pk=form.instance.pk as action_url %}
{% endif %}
<form action="{{ action_url }}" method="post" accept-charset="utf-8">
{{ form|crispy }}
{% csrf_token %}
<p><input type="submit" class="btn btn-default" value="Save"></p>
</form>
{% endblock %}
|
The variable create
is used in the title
and heading
blocks to
display different text depending on whether the template is used to create or
edit a bookmark. The URL for the form’s action
attribute is also set
according to the value of create
and assigned to action_url
. Note that
the current bookmark fetched from the database has been assigned to
form.instance
and can be used to create the edit URL for this bookmark.
Now you can add a link to create new bookmarks to the file
mysite/templates/toggle_login.html
. The corresponding line is
highlighted:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | {% if user.is_authenticated %}
<ul class="nav navbar-nav navbar-right">
<li><a href="{% url "marcador_bookmark_create" %}">Create bookmark</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
aria-expanded="false">{{ user.username }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="{% url "marcador_bookmark_user" user.username %}">
My bookmarks</a></li>
<li><a href="{% url "mysite_logout" %}">Logout</a></li>
</ul>
</li>
</ul>
{% else %}
|
The last step is to extend the template
mysite/marcador/templates/marcador/bookmark.html
at the end with the
following lines:
15 16 17 18 19 20 21 | <br>by <a href="{% url "marcador_bookmark_user" bookmark.owner.username %}">
{{ bookmark.owner.username }}</a>
{{ bookmark.date_created|timesince }} ago
{% if bookmark.owner == user or user.is_superuser %}
<br><a class="btn btn-default btn-xs" role="button"
href="{% url "marcador_bookmark_edit" bookmark.pk %}">Edit bookmark</a>
{% endif %}
|
De esta manera los usuarios autenticados pueden ver el botón de edición en sus propios marcadores.
11.5. Test the form¶
Now load the main page and click on the link to create a new bookmark. You should see this form:
It displays all fields we have configured in the form. Tags can’t be added, but you can build a second form to do this.
If you click on one the links to edit a bookmark you will see this edit form: