I have a single HTML page with 2 Django Forms in it, all in the same <form>..</form> tag. Everything works great, except when I try to upload multiple files.
Each form has their own image, and for some reason I can only save the image from the first form. Other data from the second form still gets saved, but without any image. I don't see any errors or exception raised, so I don't know what's going wrong :s.
Here's my views.py
def display_form(request):
if request.method == 'POST':
form_team = TeamForm(request.POST, request.FILES, prefix="team")
form_player = PlayerForm(request.POST, request.FILES, prefix="play")
#form_ketua = KetuaForm(request.POST, request.FILES, prefix="ketua")
if all([form.is_valid() for form in [form_team, form_player]]):
# save Team data first, overwrite if exists
try:
team = Team.objects.get(kota=form_Team.cleaned_data['name'])
team.profil = form_Team.cleaned_data['profil']
team.save()
except Team.DoesNotExist:
team = Team(**form_Team.cleaned_data)
team.save()
play = form_Player.save(commit=False)
play.name = team
play.save()
else:
form_team = TeamForm(prefix="team")
form_player = PlayerForm(prefix="play")
#form_ketua = KetuaForm(prefix="ketua")
print "a"
# list with tuple (form, legend) to pass as context
forms = [(form_Team, 'Team Data'),
(form_Player, 'Player Profile'),
]
return render_to_response(
'form/team.html',
{
'formlist': forms,
},
)
What am I doing wrong?
EDIT: Here's my template
{% extends "base.html" %}
{% block title %}Form - {{ title }}{% endblock %}
{% block content %}
<form action="." method="POST" enctype="multipart/form-data">{% csrf_token %}
{% for formitem in formlist %}
{% if formitem.1 %}
<fieldset>
<legend>{{ formitem.1 }}</legend>
{% endif %}
{{ formitem.0.non_field_errors }}
{% for field in formitem.0.visible_fields %}
<div class="formfield">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
{% if formitem.1 %}
</fieldset>
{% endif %}
{% endfor %}
<div id="formbuttons">
<input type="submit" value="Submit" class="button">
<input type="reset" value="Reset" class="button">
</div>
</form>
{% endblock %}
looks like you are missing a play.save() (you save the form with commit=False)
Related
consider this model on Django:
class My_model(models.Model):
my_choices = { '1:first' 2:second'}
myfield1=CharField()
myfield2=CharField(choices=my_choices)
Then on my form:
class My_form(forms.ModelForm):
class Meta:
model = My_model
fields = ['myfield1', 'myfield2']
My views:
def get_name(request):
if request.method == 'POST':
form = My_form(request.POST)
if form.is_valid():
return HttpResponseRedirect('/')
else:
form = My_form()
return render(request, 'form/myform.html', {'form': form})
On my template:
{% extends "base.html" %}
{% block content %}
<form action="/tlevels/" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}
On my base.html, I will load this template like this:
{% extends "base.html" %}
{% block content %}
{% load crispy_forms_tags %}
<div class="p-3 mb-2 bg-info text-white" style="margin-left:20px; margin-bottom:20px;">Status</div>
<div class="form-row" style="margin-left:20px; margin-bottom:20px; margin-top:20px;">
<div class="form-group col-md-6 mb-0">
{{ form.myfield1|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.myfield2|as_crispy_field }}
</div>
</div>
<input type="submit" class="btn btn-primary" value="Submit" style="margin-left:20px;">
</form>
{% endblock %}
What I want, is to have 2 other different templates, with whatever difference on them, and load them depending on the choice made on the ChoiceField, I guess that one way could be on the view, by adding some kind of conditional, and load a different template (html file).
Any ideas?
It is possible to use {% include %} with a variable.
def some_view_after_post(request):
# ... lookup value of myfield2 ...
return render(request, "path/to/after_post.html", {'myfield2: myfield2})
The in the after_post.html template:
<!-- include a template based on user's choice -->
<div class="user-choice">
{% include myfield2 %}
</div>
You'll want to make sure there is no possible way the user can inject an erroneous choice. For example, make sure the value of myfield2 choice is valid before adding it to the context.
I needed some validation on a Django ModelForm field. So I changed 2 lines in my models.py (just below). The validation is blocking as necessary, but I can't find the proper way to display the ValidationError. Maybe there is a cleaner way to do this in the model form ?
models.py
class Lexicon(models.Model):
[...]
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', _('Only alphanumeric characters are allowed'))
filename = models.CharField(_("Filename"), max_length=40, validators=[alphanumeric])
forms.py
class LexiconForm(forms.ModelForm):
class Meta:
model = Lexicon
fields = ['filename', 'language', 'comment', 'alphabet', 'case_sensitive', 'diacritics']
views.py
#login_required
def new_pls_view(request):
if request.method == 'POST':
form = LexiconForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.user = request.user
obj.save()
return redirect('pls_edit')
else:
form = LexiconForm()
return render(request, 'main/new_pls.html', {
'form': form,
})
template.html
<form class="form-horizontal" method="post" action="{% url 'new_pls' %}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
[...]
{% if form.is_bound %}
{% if form.filename.errors %}
{% for error in form.filename.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% endif %}
{% if form.filename.help_text %}
<small class="form-text text-muted">{{ form.filename.help_text }}</small>
{% endif %}
{% endif %}
{% render_field form.filename type="text" class+="form-control" id="plsFilename" placeholder=form.filename.label %}
Replacing my entire form by {{ form }} as #Alasdair suggested is working, so I guess something is wrong with my template rendering.
I've simply replaced my error printing by this and the error prints!
<form class="form-horizontal" method="post" action="{% url 'new_pls' %}">
{% csrf_token %}
{{ form.non_field_errors }}
[...]
{{ form.filename.errors }}
{% render_field form.filename type="text" class+="form-control" id="plsFilename" placeholder=form.filename.label %}
I got a question regarding the validation of a dynamically added inline formset in Django. It seems like I am missing something in my implementation.
Here is my case:
My project is a team management platform. A team is called Crew and can have several time Schedules. Each Schedule can have several Shifts. Please take a look at my code. At the moment I am able to create a schedule with several, dynamically added forms of the formset for the Shifts, if all fields are valid.
If not, the error for the Shift forms is not displayed and it is filled with the initial data again. It looks like the data of the shift forms is not bound after sending the POST request (because form.is_bound() is false). Moreover the data of Shift forms is not populated again after the POST request.
What do you think is the cause of this behaviour? Do I have to overwrite the is_valid function? I dont know, because it looks like the function works fine - the data is just not bound correctly to the new forms.
Views.py
def schedule_add(request, crew_id):
if request.method == "GET":
form = ScheduleForm()
ShiftFormSet = formset_factory(ShiftForm)
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
elif request.method == "POST":
form = ScheduleForm(request.POST)
numberOfShifts = int(request.POST['form-TOTAL_FORMS'])
ShiftFormSet = formset_factory(ShiftForm, extra=numberOfShifts)
shift_formset = ShiftFormSet(request.POST, prefix='form')
print(request.POST)
if form.is_valid() and shift_formset.is_valid():
schedule = Schedule()
schedule.name = form.cleaned_data.get('name')
schedule.crew = Crew.objects.get(pk=crew_id)
schedule.location = form.cleaned_data.get('location')
schedule.subperiod = form.cleaned_data.get('sub_period')
schedule.save()
for shift_form in shift_formset:
if shift_form.is_valid():
shift = Shift()
shift.min_user_count = shift_form.cleaned_data.get('min_user_count')
shift.max_user_count = shift_form.cleaned_data.get('max_user_count')
shift.start_datetime = shift_form.cleaned_data.get('start_time')
shift.end_datetime = shift_form.cleaned_data.get('end_time')
shift.schedule = schedule
shift.save()
messages.success(request, 'Zeitplan & Schichten angelegt.')
return redirect('shifter:crew_view', crew_id=crew_id)
else:
messages.error(request, 'Fehler')
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
else:
return redirect('shifter:index')
forms.py
class ScheduleForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True, help_text='', label="Name")
sub_period = forms.ModelChoiceField(queryset=SubPeriod.objects.all(), empty_label=None, label="Tag")
location = forms.ModelChoiceField(queryset=Location.objects.all(), empty_label=None, label="Einsatzort")
class Meta:
model = Schedule
fields = ('name', 'sub_period', 'location',)
class ShiftForm(forms.ModelForm):
min_user_count = forms.IntegerField(required=True, help_text='', label="Min Count", initial=2)
max_user_count = forms.IntegerField(required=True, help_text='', label="Max Count", initial=4)
start_time = forms.DateTimeField(required=True, help_text='', label="Shift start", initial=datetime.now)
end_time = forms.DateTimeField(required=True, help_text='', label="Shift end", initial=datetime.now)
class Meta:
model = Shift
fields = ('start_time','end_time','min_user_count','max_user_count',)
Template
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endfor %}
<h2 class="mt-5">Shifts</h2>
<table class="table">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
<th></th>
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% if form.is_bound %}
{% if form.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in form.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
</td>
{% endfor %}
<td></td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">Save</button>
</form>
Thanks in advance,
Christopher
You're returning the class, ShiftFormSet, to the template (in the third-from-last line of your code) instead of the instance, shift_formset.
I'm attempting to set up a Django Form Wizard, but I'm having trouble getting it to work. I've followed the example, from the Django website, but can't get anything to work. When I go to the URL that should have my multistep form, only the template html thats extended shows up. What am I doing wrong here?
FORMS.PY
class ScheduleDate(forms.Form):
date = forms.CharField()
class ScheduleTime(forms.Form):
time = forms.CharField()
VIEWS.PY
FORMS =[('date', ScheduleDate),
('time', ScheduleTime)]
TEMPLATES = [('date', 'main/schedule_date2.html'),
('time', 'main/schedule_time.html')]
class ContactWizard(SessionWizardView):
def get_template_name(self):
return TEMPLATES[self.steps.current]
def done(self, form_list, **kwargs):
print 'testing'
return HttpResponseRedirect('main/home.html')
URLS.PY
urlpatterns = patterns('',
url(r'^checkout/$', views.ContactWizard.as_view([ScheduleDate, ScheduleTime]), name='checkout'))
SCHEDULE_DATE2.HTML(From the Django Website)
{% extends "base.html" %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% 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 }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>
{% endblock %}
Thanks!
I am trying to create a form in Django with the form wizard where there are multiple (repeating) formsets in the same step of the wizard.
What I have is:
# forms.py
class FormStep1A(forms.Form):
answerA = forms.CharField(max_length=100)
remarkA = forms.CharField(widget=forms.Textarea)
class FormStep1B(forms.Form):
answerB = forms.CharField(max_length=100)
remarkB = forms.CharField(widget=forms.Textarea)
class FormStep1(forms.Form):
partA = formset_factory(FormStep1A)
partB = formset_factory(FormStep1B)
and
# urls.py
STEPS = (
('1', FormStep1),
# ...
)
# FormWizard is a subclass of NamedUrlSessionWizardView
wizard = FormWizard.as_view(STEPS, url_name='form_new_step')
urlpatterns = patterns(
'',
url(r'^new/(?P<step>.+)/$', wizard,
name='form_new_step'),
url(r'^new/$', wizard, name='form_new'),
)
And my template looks the same as in the documentation. However, my form is rendered empty with no fields at all.
I know there are similar questions or recipes out there:
Django formwizard with formsets and forms on same page
django wizard, using form and formset in the same step
Combining a Form and a FormSet in Django: How to pass them in the context?
But I just cannot get this to work. Any help is much appreciated, thank you!
UPDATE: My template looks like this:
{% extends 'base.html' %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<div class="row">
<div class="large-12 columns">
<h3>{% trans "Questionnaire" %}</h3>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
{% csrf_token %}
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
{% if wizard.steps.prev %}
<button class="button tiny" name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "First step" %}</button>
<button class="button tiny" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "Prev step" %}</button>
{% endif %}
<input class="button tiny" type="submit" value="{% trans "Submit" %}"/>
</form>
</div>
</div>
{% endblock %}