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!
Related
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.
Im trying to create a form where the user selects from a gallery of images and it saves it to the database. The code below currently renders some radio buttons in the html output. Is there anyway I can change these to images i have saved in a static directory so the user can click on images instead? Would be great if I could change what it saves in the database to what I needed instead of image urls as well. Theres lots of documentation on uploading images but not much I could find on selecting images. Im using django 1.9.7 and python 3.5
models.py
client_choices = (('client1', 'Client 1'),
('client2', 'Client 2'),
('client3', 'Client 3'),
('client4', 'Client 4'),
('client5', 'Client 5'))
class ClientSelect(models.Model):
client = MultiSelectField(choices=client_choices)
forms.py
from app.models import ClientSelect
class ClientSelectForm(forms.ModelForm):
class Meta:
model = ClientSelect
fields = '__all__'
views.py
class FormWizard(SessionWizardView):
template_name = "app/clientchoices.html"
#define what the wizard does when its finished collecting information
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render_to_response('app/about.html', {'form_data': form_data})
urls.py
url(r'^clientchoices$', FormWizard.as_view([ClientSelectForm]) , name='clientchoices'),
clientchoices.html
{% load staticfiles %}
{% block content %}
<section class="content">
<div class="container">
<div class="fit-form-wrapper">
<h2>Client Choices</h2>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
{% for field in form %}
{{field.error}}
{% endfor %}
<form action="{% url 'clientchoices' %}" 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 class="btn btn-brand" name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">"First Step"</button>
<button class="btn btn-brand" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">"Previous Step"</button>
{% endif %}
<input class="btn btn-brand" type="submit" value="Submit" />
</form>
</div>
</div>
</section>
{% endblock %}
Any help is appreciated thank you
I'm trying to rewrite my function based view to class based view. It raises this error:
.../test/User1
'UserDetailView' object has no attribute 'rindex'
The problem is probably obvious, I'm new in class based views.
So what to do to be able get any profile using url .../test/username?
My new view:
class UserDetailView(DetailView):
model = User
def get_object(self, queryset=None):
return get_object_or_404(self.model, pk=self.kwargs["pk"])
URLS.PY:
url(r'^test/(?P<username>[a-zA-Z0-9]+)/$', views.UserDetailView(),name="user_detail"),
And template:
{% extends "base.html" %}
{% block content %}
{{ userprofile.as_p }}
{% endblock %}
My old view is this:
def get_user_profile(request, username):
user = User.objects.get(username=username)
jobs = user.jobs.all()
table = MyJobsTable(jobs)
context = {
'my_jobs': table,
"user": user
}
return render(request, 'auth/profiles/my-profile.html', context=context)
And HTML:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load render_table from django_tables2 %}
{% block content %}
{% if user.is_authenticated %}
<h3>{% if user.userprofile.is_translator %} Prekladateľský účet: {% else %} Štandardný
účet: {% endif %}{{ user.username }} </h3>
<ul>
<li>Username: {{ user.username }}</li>
<li>First name: {{ user.first_name }}</li>
<li>Last name: {{ user.last_name }}</li>
<li>Email: {{ user.email }}</li>
<li>Telephone: {{ user.userprofile.telephone }}</li>
<li>Languages: {{ user.userprofile.languages.as_p }}</li>
{# TODO: DOPLNIT ATRIBUTY + ked je aj translator#}
</ul>
{% if user.jobs %}
<p>My Jobs</p>
{% render_table my_jobs %}
{% else %}
<p>You have no jobs</p>
{% endif %}
<form class="navbar-form navbar-right" action="/edit-profile" method="get">
<button type="submit" class="btn btn-success">Edit Your Profile</button>
</form>
<form class="navbar-form navbar-right" action="/register-as-translator" method="get">
<button type="submit" class="btn btn-success">Become A Translator</button>
</form>
{% endif %}
{% endblock %}
URLS.PY:
url(r'^profile/(?P<username>[a-zA-Z0-9]+)/$', views.get_user_profile)
The issue is in your urls.py. With a class-based view, you always need to use the as_view classmethod:
url(r'^test/(?P<username>[a-zA-Z0-9]+)/$', views.UserDetailView.as_view(), name="user_detail"),
I am trying to use Crispy forms with Django-userena to make it look better but when ever I put the Crispy form tags in it duplicates the form,
My code is as followed:
{% extends 'userena/base_userena.html' %}
{% load i18n %}
{% load url from future %}
{% load crispy_forms_tags %}
{% block title %}{% trans "Signin" %}{% endblock %}
{% block content %}
<form action="" method="post" class="formholder">
{% csrf_token %}
{{ form|crispy }}
<fieldset>
<legend>{% trans "Signin" %}</legend>
{{ form.non_field_errors }}
{% for field in form %}
{{ field.errors }}
{% comment %} Displaying checkboxes differently {% endcomment %}
{% if field.name == 'remember_me' %}
<p class="checkbox">
<label for="id_{{ field.name }}">{{ field }} {{ field.label }}</label>
</p>
{% else %}
<p>
{{ field.label_tag }}
{{ field }}
</p>
{% endif %}
{% endfor %}
</fieldset>
<input type="submit" value="{% trans "Signin" %}" />
<p class="forgot-password">{% trans "Forgot your password?" %}</p>
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
</form>
{% endblock %}
Solution by OP.
The problem was that the, {{ form|crispy }} was actually creating the form in the form.py file all I had to do was remove all the other from tags and just keep the {{ form|crispy }}
Here is what it looks like:
{% extends 'userena/base_userena.html' %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans "Signin" %}{% endblock %}
{% block content %}
{% load crispy_forms_tags %}
<form action="" method="post" class="formholder">
{% csrf_token %}
<fieldset>
<legend>{% trans "Signin" %}</legend>
{{ form|crispy }}
</fieldset>
<input type="submit" value="{% trans "Signin" %}" />
<p class="forgot-password">{% trans "Forgot your password?" %}</p>
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
</div>
</form>
{% endblock %}
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 %}