formtools - ¿Forma la información inicial del asistente para que la edición no se cargue correctamente en Django?
form wizard django (1)
Tengo una lista de tres páginas que sale de un solo modelo. Pude guardar el modelo por primera vez, pero cuando quiero editar el modelo, solo el primer formulario muestra el valor inicial, los formularios posteriores no muestran los datos iniciales. pero cuando initial_dict
el initial_dict
desde las vistas, puedo ver todas las vistas iniciales correctamente. Seguí este blog en el asistente de formularios.
Aquí está mi model.py:
class Item(models.Model):
user=models.ForeignKey(User)
price=models.DecimalField(max_digits=8,decimal_places=2)
image=models.ImageField(upload_to="assets/", blank=True)
description=models.TextField(blank=True)
def __unicode__(self):
return ''%s-%s'' %(self.user.username, self.price)
urls.py:
urlpatterns = patterns('''',
url(r''^create/$'', MyWizard.as_view([FirstForm, SecondForm, ThirdForm]), name=''wizards''),
url(r''^edit/(?P<id>/d+)/$'', ''formwizard.views.edit_wizard'', name=''edit_wizard''),
)
forms.py:
class FirstForm(forms.Form):
id = forms.IntegerField(widget=forms.HiddenInput, required=False)
price = forms.DecimalField(max_digits=8, decimal_places=2)
#add all the fields that you want to include in the form
class SecondForm(forms.Form):
image = forms.ImageField(required=False)
class ThirdForm(forms.Form):
description = forms.CharField(widget=forms.Textarea)
views.py:
class MyWizard(SessionWizardView):
template_name = "wizard_form.html"
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT))
#if you are uploading files you need to set FileSystemStorage
def done(self, form_list, **kwargs):
for form in form_list:
print form.initial
if not self.request.user.is_authenticated():
raise Http404
id = form_list[0].cleaned_data[''id'']
try:
item = Item.objects.get(pk=id)
###################### SAVING ITEM #######################
item.save()
print item
instance = item
except:
item = None
instance = None
if item and item.user != self.request.user:
print "about to raise 404"
raise Http404
if not item:
instance = Item()
for form in form_list:
for field, value in form.cleaned_data.iteritems():
setattr(instance, field, value)
instance.user = self.request.user
instance.save()
return render_to_response(''wizard-done.html'', {
''form_data'': [form.cleaned_data for form in form_list], })
def edit_wizard(request, id):
#get the object
item = get_object_or_404(Item, pk=id)
#make sure the item belongs to the user
if item.user != request.user:
raise HttpResponseForbidden()
else:
#get the initial data to include in the form
initial = {''0'': {''id'': item.id,
''price'': item.price,
#make sure you list every field from your form definition here to include it later in the initial_dict
},
''1'': {''image'': item.image,
},
''2'': {''description'': item.description,
},
}
print initial
form = MyWizard.as_view([FirstForm, SecondForm, ThirdForm], initial_dict=initial)
return form(context=RequestContext(request), request=request)
modelo:
<html>
<body>
<h2>Contact Us</h2>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
{% for field in form %}
{{field.error}}
{% endfor %}
<form action={% url ''wizards'' %} method="post" enctype="multipart/form-data">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">"first step"</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"prev step"</button>
{% endif %}
<input type="submit" value="Submit" />
</form>
</body>
</html>
EDITAR: uno que noté es el siguiente: en el modo de edición, es decir, cuando estoy en la siguiente url: http://127.0.0.1:8000/wizard/edit/1/
, muestra los primeros datos del formulario correctamente, y cuando hago clic en enviar, no me lleva al paso 2 del modo de edición, es decir, la URL cambia a http://127.0.0.1:8000/wizard/create/
.
Si al hacer submit
en submit
en edit url (como /wizard/edit/1
) en el primer paso, se mantiene la misma URL, entonces el formulario obtendría sus datos iniciales en el siguiente paso. pero no puedo imaginar cómo evitar que la URL cambie a /wizard/create
El error parece trivial. En su plantilla, la acción del formulario tiene url de wizards
, que es url de crear vista. Por lo tanto, cuando se envía el formulario va a /wizard/create
.
Para poder usar la plantilla para ambas vistas, puede eliminar el atributo de action
de la etiqueta del form
. El formulario se enviará a la URL actual que se puede crear o editar.
Así que cambie su plantilla para tener una etiqueta de form
como
<form method="post" enctype="multipart/form-data">
EDITAR: para guardar el artículo
Actualiza tu vista como:
def done(self, form_list, **kwargs):
for form in form_list:
print form.initial
if not self.request.user.is_authenticated():
raise Http404
id = form_list[0].cleaned_data[''id'']
try:
item = Item.objects.get(pk=id)
print item
instance = item
except:
item = None
instance = None
if item and item.user != self.request.user:
print "about to raise 404"
raise Http404
if not item:
instance = Item()
#moved for out of if
for form in form_list:
for field, value in form.cleaned_data.iteritems():
setattr(instance, field, value)
instance.user = self.request.user
instance.save()
return render_to_response(''wizard-done.html'', {
''form_data'': [form.cleaned_data for form in form_list], })