Utilizamos cookies propias y de terceros para hacer funcionar y mejorar nuestros servicios. Si continúa navegando, consideramos que acepta su uso. Puede obtener más información visitando nuestra política de cookies.
DJANGO - FORMULARIOS ASOCIADOS A MODELOS
En esta sesión demostramos el uso de la clase ModelForm para definir formularios directamente asociados a modelos de Django, y cómo aprovecharlos en conjunto con las vistas genéricas basadas en clases, para implementar funcionalidades comunes en muchas aplicaciones web con un mínimo de esfuerzo de programación.
Cargando video...
NOTA: Solo puedes ver una versión limitada del video a baja resolución, si quieres ver la versión completa por favor regístrate y obtén alguno de nuestros planes!
Descripción del Vídeo
Con Django, podemos usar la clase ModelForm para configurar de manera sencilla formularios asociados a nuestros modelos de base de datos.
Al combinar esta funcionalidad con las clases de vistas genéricas, podemos generar formularios y vistas completas con muy poco esfuerzo de desarrollo.
En este ejemplo, ilustraremos el uso de formularios asociados a modelos con vistas genéricas, para agregar en la propia aplicación la funcionalidad de agregar/editar preguntas y opciones (aunque ya existe en el sitio administrativo)
Usaremos el paquete django-bootstrap3-datetimepicker para incluir un control de calendario compatible con Bootstrap.
Código disponible en:
https://github.com/networkfaculty/Fundamentos-Django/releases/tag/d-2.3.9
Instalar paquete de calendario (versión mas reciente):
pip install git+https://github.com/nkunihiko/django-bootstrap3-datetimepicker.git
Agregar bootstrap3_datetime a INSTALLED_APPS en curso/settings.py
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap3',
'bootstrap3_datetime',
'encuestas',
)
curso/encuestas/forms.py
from django import forms
from .models import Pregunta, Opcion
from bootstrap3_datetime.widgets import DateTimePicker
from django.forms.models import inlineformset_factory
class FormContacto(forms.Form):
asunto = forms.CharField(max_length=100)
mensaje = forms.CharField(widget=forms.Textarea)
remitente = forms.EmailField()
cc_remitente = forms.BooleanField(label='Envíame una copia', required=False)
class FormPregunta(forms.ModelForm):
class Meta:
model = Pregunta
fields = ['texto_pregunta','fe_publicacion']
widgets = {'texto_pregunta': forms.Textarea(attrs={'rows':3}),
'fe_publicacion': DateTimePicker(options={"format": "YYYY-MM-DD",
"pickTime": False})}
FormPreguntaOpciones = inlineformset_factory(
Pregunta,
Opcion,
fields = ('texto_opcion',),
max_num = 5,
extra = 5,
)
Usar formularios asociados a modelos con clases genéricas en curso/encuestas/views.py
...
from .forms import *
from django.views.generic.edit import CreateView, UpdateView
...
class VistaCrearPregunta(CreateView):
model = Pregunta
form_class = FormPregunta
template_name = 'encuestas/agregar_pregunta.html'
success_url = reverse_lazy('encuestas:index')
class VistaEditarPregunta(UpdateView):
model = Pregunta
form_class = FormPregunta
template_name = 'encuestas/editar_pregunta.html'
success_url = reverse_lazy('encuestas:index')
class VistaOpciones(UpdateView):
'''
En este ejemplo utilizamos un Formset personalizado para editar las opciones
correspondientes a una pregunta. Por ello, utilizamos el modelo "padre" (Pregunta),
y personalizamos los métodos get/post para obtener y guardar la lista de opciones
'''
model = Pregunta
form_class = FormPregunta
template_name = 'encuestas/editar_opciones.html'
success_url = reverse_lazy('encuestas:index')
def get(self, request, *args, **kwargs):
self.object = self.get_object()
opciones_form = FormPreguntaOpciones(instance=self.object)
return self.render_to_response(
self.get_context_data(opciones_form=opciones_form,))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
opciones_form = FormPreguntaOpciones(request.POST, instance=self.object)
if opciones_form.is_valid():
opciones_form.save()
messages.success(request, 'Opciones guardadas')
return HttpResponseRedirect(self.get_success_url())
else:
messages.error(request, 'No se pudieron guardar las opciones')
return self.render_to_response(
self.get_context_data(opciones_form=opciones_form,))
Plantilla para agregar pregunta en curso/encuestas/templates/encuestas/agregar_pregunta.html
{% extends 'encuestas/base.html' %}
{% block extra-head %}
{{ form.media }}
{% endblock%}
{% block contenido %}
{% load bootstrap3 %}
<h2>Agrega una nueva pregunta</h2>
<form action="{% url 'encuestas:agregar' %}" method="post">
{% csrf_token %}
{% bootstrap_form form layout='horizontal' %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "floppy-disk" %} Agregar Pregunta
</button>
{% endbuttons %}
</form>
{% endblock contenido %}
Agregar bloque personalizable en el <head> desde curso/encuestas/templates/encuestas/base.html
<script src="{% static 'encuestas/js/jquery-1.11.3.min.js' %}"></script>
<script src="{% static 'encuestas/js/bootstrap.min.js' %}"></script>
{% block extra-head %}{% endblock %}
</head>
Agregar botones para editar en vista de detalle curso/encuestas/templates/encuestas/detalle.html
…
<a class="btn btn-info" href="{% url 'encuestas:resultados' pregunta.id %}">
Ver resultados
</a>
<a class="btn btn-default" href="{% url 'encuestas:editar' pregunta.id %}">
{% bootstrap_icon "pencil" %} Editar Pregunta
</a>
<a class="btn btn-default" href="{% url 'encuestas:opciones' pregunta.id %}">
{% bootstrap_icon "pencil" %} Editar Opciones
</a>
…
curso/encuestas/templates/encuestas/editar_opciones.html
{% extends 'encuestas/base.html' %}
{% load bootstrap3 %}
{% block contenido %}
<h2>Editar Opciones para pregunta #{{ pregunta.id }}</h2>
<h4>{{ pregunta.texto_pregunta }}</h4>
<form action="{% url 'encuestas:opciones' pregunta.id %}" method="post">
{% csrf_token %}
{% bootstrap_formset opciones_form %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "floppy-disk" %} Guardar Cambios
</button>
{% endbuttons %}
</form>
{% endblock contenido %}
curso/encuestas/templates/encuestas/editar_pregunta.html
{% extends 'encuestas/base.html' %}
{% load bootstrap3 %}
{% block extra-head %}
{{ form.media }}
{% endblock%}
{% block contenido %}
<h2>Editar pregunta #{{ pregunta.id }}</h2>
<form action="{% url 'encuestas:editar' pregunta.id %}" method="post">
{% csrf_token %}
{% bootstrap_form form layout='horizontal' %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "floppy-disk" %} Guardar Cambios
</button>
{% endbuttons %}
</form>
{% endblock contenido %}
Agregar botones para editar y agregar en curso/encuestas/templates/encuestas/index.html
...
href="{% url 'encuestas:detalle' pregunta.id %}">Votar</a>
<a class="btn btn-info" role="button"
href="{% url 'encuestas:resultados' pregunta.id %}">Ver resultados</a>
<a class="btn btn-default" role="button"
href="{% url 'encuestas:editar' pregunta.id %}">
{% bootstrap_icon "pencil" %} Editar Pregunta</a>
</div>
</li>
{% endfor %}
...
<p>No hay encuestas disponibles.</p>
{% endif %}
<a class="btn btn-default" role="button"
href="{% url 'encuestas:agregar' %}">{% bootstrap_icon "plus" %} Nueva Encuesta</a>
...
Agregar nuevas rutas en curso/encuestas/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
# ej: /encuestas/
url(r'^$', views.VistaIndex.as_view(), name='index'),
# ej: /encuestas/5
# Las vistas detalladas genéricas esperan que el argumento se llame 'pk'
url(r'^(?P<pk>\d+)/$', views.VistaDetalle.as_view(), name='detalle'),
# ej: /encuestas/5/resultados
url(r'^(?P<pk>\d+)/resultados$', views.VistaResultados.as_view(), name='resultados'),
# ej: /encuestas/5/votar
url(r'^(?P<id_pregunta>\d+)/votar$', views.votar, name='votar'),
url(r'^contacto$', views.contacto, name='contacto'),
url(r'^agregar$', views.VistaCrearPregunta.as_view(), name='agregar'),
url(r'^(?P<pk>\d+)/editar', views.VistaEditarPregunta.as_view(), name='editar'),
url(r'^(?P<pk>\d+)/opciones', views.VistaOpciones.as_view(), name='opciones'),
]
Rating
Global
comments powered by Disqus