Bind dynamic choices to ModelForm in Django - django

I'm trying to bind a dynamic list of choices to a ModelForm. The form is rendered correctly. However, when using the form with a POST Request, I get an empty form back. My goal is to save that form into the database (form.save()). Any help would be much appreciated.
Model
I'm using a multiple choice select field ( https://github.com/goinnn/django-multiselectfield )
from django.db import models
from multiselectfield import MultiSelectField
class VizInfoModel(models.Model):
tog = MultiSelectField()
vis = MultiSelectField()
Forms
class VizInfoForm(forms.ModelForm):
class Meta:
model = VizInfoModel
fields = '__all__'
def __init__(self,choice,*args,**kwargs):
super(VizInfoForm, self).__init__(*args,**kwargs)
self.fields['tog'].choices = choice
self.fields['vis'].choices = choice
View
Choices are passed from the view when instantiating the form.
def viz_details(request):
options = []
headers = request.session['headers']
for header in headers :
options.append((header, header))
if request.method == 'POST':
form = VizInfoForm(options, request.POST)
#doesnt' get into the if statement since form is empty!
#choices are not bounded to the model although the form is perfectly rendered
if form.is_valid():
form.save()
return HttpResponseRedirect('/upload')
else:
#this works just fine
form = VizInfoForm(options)
return render(request, 'uploads/details.html', {'form': form})
Template
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>Choose variables to toggle between</p>
{{ form.tog }}
<br></br>
<p>Choose variable to be visualized</p>
{{ form.vis }}
<br></br>
<button type="submit">Submit</button>
</form>

You're saying Django doesn't get into your if request.method == 'POST' block.
This tells us that you're not sending your request through the POST method. Your template probably has an error in it, maybe you haven't specified the method on your form, or you made your button to just be a link instead of a submit ?
Show your template so we can say more, unless this was enough to solve your question !

Related

how to make a post request and get the radio button values in django

I'm doing a website in django but this is the first time i use this framework so i'm not so used to it. I need to save some information on a DB, and i need to take these information from some radio buttons. I tryied so many ways to get the data but nothing worked. So i'd like to ask how to get these data in models.py from a template.html.
This is the code in views.py:
def question1(request):
form = CHOICES(request.POST)
if request.method == 'POST':
form = CHOICES(request.POST)
if form.is_valid():
selected = form.cleaned_data.get("NUMS")
return render(request, 'q1.html', {'form': form})
This is the template question1.html:
<form class="form-inline" method='POST' action="" enctype='multipart/form-data'>{% csrf_token %}
{% csrf_token %}
{{form.path}}
</form>
Then there is the form in forms.py:
NUMS = [
('one', 'one'),
('two', 'two'),
('three', 'three'),
('four', 'four'),
('five', 'fives'),
]
class CHOICES(forms.Form):
NUMS = forms.ChoiceField(choices=NUMS, widget=forms.RadioSelect)
I checked and I think that the problem could be the request.method that is GET insted of POST.
So how can I make a POST request?
Thank you

How to query database based on user inputs and show results in another page?

Good day everyone.
I am trying to build a form which queries the database based on user data inputs and then returns the results in a new page. but I don't know exactly how to do it and I am getting errors. I've looked for a solution but couldn't find any. Please help me if you know any solutions.
Thanks in advance.
Here are my codes:
forms.py
class AttendanceForm(forms.Form):
course = forms.CharField(max_length=50)
department = forms.CharField(max_length=10)
semester = forms.IntegerField()
views.py
class AttendanceForm(generic.FormView):
form_class = CrsAttForm
template_name = 'office/crsatt_form.html'
success_url = reverse_lazy('office:members_list')
class MembersList(generic.ListView):
template_name = "office/crs_att.html"
context_object_name = 'members'
def get_queryset(self):
return Members.objects.all()
# I know I should use .filter method but how could I set the parameters to data received from the form
urls.py
url(r'^CourseAttendanceForm/$', views.AttendanceForm.as_view(), name='courseattendance'),
url(r'^CourseAttendanceForm/Results/$',views.MembersList.as_view(), name='memebrs_list'),
I think that it will be easier for you to use function based views for this one.
You can do it like this:
views.py
def form_page(request):
form = AttendanceForm()
# you get to this "if" if the form has been filled by the user
if request.method == "POST":
form = AttendanceForm(request.POST)
if form.is_valid():
course = request.POST['course']
department = request.POST['department']
semester = request.POST['semester']
members = Member.objects.filter(#here you do your filters as you already have the course, department and semester variables)
context = {'members': members}
return render(request, 'second_page.html', context)
# if the form hasn't been filled by the user you display the form
context = {'form': form}
return render(request, 'form_page.html', context)
form_page.html
<form method="post" action="{% url 'form_page' %}">
{% csrf_token %}
{{ form }}
<button type="submit">Search!</button>
</form>
urls.py
path('form_page/', views.form_page, name='form_page')
second_page.html
{% for member in members %}
# here you display whatever you want to
{% endfor %}

Retrieve selected choices from Django form ChoiceField

I'm attempting to make a search functionality on my Django web app. The idea is that users will go to the front page and be able to select from a drop down list of properties (ie. the OS, compiler, etc) and then submit their search which should return a list of matching builds. I have the ChoiceField form set up and I know the code I need to run to get the proper build in my next view. What I don't know is how to pass the values the user selected when they hit submit to the next view so I can filter based on those choices. Any help?
forms.py
from .models import *
class BuildForm(forms.Form):
build_OPTIONS = Builds.objects.values().distinct()
...
Build_type = forms.ChoiceField(widget=forms.Select(), choices=build_OPTIONS)
views.py
from .forms import BuildForm
def index(request):
builds = BuildForm()
return render(request, 'ReportGenerator/index.html',
{"builds":builds})
templates/App/index.html
{% if builds %}
<h2>Pick a Build</h2>
<form method="POST" class="build-form">{% csrf_token %}
{{ builds.as_p }}
</form>
{% else %}
<p>No reports are available.</p>
{% endif %}
For your build_OPTIONS that you use as choices, it would probably be best to define them inside the model like this. And then you can reference them in your form class like so:
models.py
class Builds(models.Model):
CHOICE1 = "Choice 1"
CHOICE2 = "Choice 2"
BUILD_OPTIONS_CHOICES = (
(CHOICE1, 'Choice 1'),
(CHOICE2, 'Choice 2'),
(<value>, <human readable name>),
)
...fields...
forms.py
from .models import *
class BuildForm(forms.Form):
...
Build_type = forms.ChoiceField(widget=forms.Select(), choices=Builds.BUILD_OPTIONS_CHOICES)
Here's an example for the view. If form.is_valid() returns True then you can access the form values in form.cleaned_data['my_form_field_name']
views.py
def index(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = BuildForm(request.POST)
# check whether it's valid:
if form.is_valid():
# can access the form data in cleaned_data['form_field_name']
print form.cleaned_data['build_type']
# redirect to a new URL:
return HttpResponseRedirect('/')
# if a GET (or any other method) we'll create a blank form
else:
form = BuildForm()
return render(request, 'index.html', {'form': form})
As for the form field name, it's probably build_options and build_type. Usually it uses whatever the variable name is in the form class. To make life easier, I would standardize on all lowercase characters with underscores for the variable names, capitalized first letters for class names, all uppercase for constants, etc. For more information see this page where it describes how as_p() works.

Render Django formset as array

I have a model and i need to create form with multiple instances in it. To be more specific: i need to render my ModelForm inside regular form with square brackets next to it's fields names. Something like this in magicworld:
forms.py
class ManForm(ModelForm):
class Meta:
model = Man
fields = ['name', 'age']
class PeopleForm(forms.Form):
# modelless form
people = ??? # array of ManForm instances or something
form.html
<form action="/people/create/">
{{ form }}
</form>
output
<form action="/people/create/">
<input type="text" name="name[0]"/>
<input type="text" name="age[0]"/>
</form>
To tell you the truth, i don't know how to approach this problem at all. I tried modelformset_factory, but all i've got is <input type="text" name="form-0-name"/>
As discussed in the comments, you need a formset.
def create_people(request):
PeopleFormSet = modelformset_factory(Man, form=ManForm)
if request.method == 'POST':
formset = PeopleFormSet(request.POST)
if formset.is_valid():
for form in formset:
... do something with individual form
else:
formset = PeopleFormSet()
return render(request, template_name, {'formset': formset}
For using formsets in function based views see #Daniel Roseman 's answer or read up here.
For class based views there is no built in generic view for this. According to this ticket they decided to let third-party-packages handle that. You can use django-extra-views for that.

Disable validation when calling form for the first time

I am struggling a bit with my Django forms. When I call my form site, always validation errors appear (this field is required). I'd prefer to see this message after clicking the submit button, if a field is not filled like a javascript function would do. In addition I'm using regex for validation, which is working fine.
I am working with CVBs. Here is some code:
models.py
class Institute(models.Model):
name = models.CharField(max_length=50)
timestamp = models.DateTimeField(auto_now_add=True)
views.py
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
forms.py
class InstituteForm(forms.ModelForm):
name= forms.CharField(error_messages={'required': 'Own Error Text'}, validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$', message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Hope someone has an idea on how to fix it.
edit1:
my template is quite simple
{% block pagetitle %}Institutes{%endblock %}
{% block content %}
<form class="form-horizontal" name="form_group" method="post">
{% csrf_token %}
<div>
{{ form.as_p }}
</div>
<input class="btn btn-primary" type="submit" value="click me" />
</form>
{% endblock %}
and my url config:
urlpatterns = patterns('',
url(r'^institute_create/$', views.InstituteCreate.as_view(), name='institute_create'),
)
I'm new to Django development so i'll try to explain the problem more detailed:
On my website, when i open the link www.exampleurl.com/institute_create my form is shown. Then i see the field where i have to enter the name for the institute. Above this field the text "this field is required" is displayed. But i don't want to see this, until i try to submit an empty form.
When i enter some text which doesnt match and i press submit button the error text field changes its message to forbidden string as expected.
Unless you're using a POST request to your view, form validation won't be triggered. There's likely an error somewhere else in your code, however, there are couple of things about your code that you'll want to address:
Classes in Python should always begin with an upper-case letter and follow the CapWords convention:
class Institute(models.Model):
name = models.CharField(max_length=50)
# just use the built-in `auto_now_add` argument
timestamp = models.DateTimeField(auto_now_add=True)
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
class InstituteForm(forms.ModelForm):
# All Django model/form fields are required by default, so you
# can drop the `required=True` here
name= forms.CharField(validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$',
message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Otherwise, it's impossible to tell the difference between the class definition and an instance of the class, and you're a lot less likely to run into collisions.
Just out of curiosity, are you seeing in-browser HTML5 validation errors versus errors from Django? If you can add your template code to your question it might help.
I know this is a very old question, but I don't see it answered. I am a beginner in django too and I was following the Django tutorial when I faced the same issue.
I resolved it this way:
if 'voteButton' in request.POST:
context = {
'question': question,
'error_message': "You didn't select a choice"
}
return render(request, 'polls/details.html', context)
elif:
# do something else. Display error message
voteButton is the name of the 'submit' button in your form. Hope this helps! Please do let me know if this approach is wrong.
As Brandon mentioned, your form gets validated on a POST request. So ensure that during the first visit of the page, the Form doesn't get bound to a POST request.
For example, don't do this :
def register(request):
form = RegistrationForm(request.POST)
if request.method == 'POST':
if form.is_valid():
# Do something
return render(request, 'register.html', {'form': form})
You should bind the form to a POST request only if the page is accessed via a POST request. This should help:
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# DO something
else :
form = RegistrationForm()
return render(request, 'register.html', {'form': form})