Flask edit form submit truble - python

Objects
class MyObj:
def __init__(self, data_dict):
self.id = ''
self.name = ''
self.minDescription = ''
self.descriptions = ''
class MyObjForm(Form):
name = StringField('name')
minDescription = StringField('minDescription')
descriptions = TextAreaField('descriptions')
Routings
This good work in "POST" and "GET" mode. Submit button have a good reactions when click.
#app.route("/create", methods=["GET", "POST"])
#login_required
def create():
if request.method == 'POST':
form = MyObjForm(request.form)
if form.validate():
new_obj = MyObj(request.form)
return redirect(url_for("/"))
else:
return render_template('create.html', form=form)
else:
return render_template('create.html', form=MyObjForm())
When i route in "GET" mode my code is good work and view have old object data but click on submit button is not have any reactions.
#app.route("/edit/<id>", methods=["GET", "POST"])
#login_required
def edit(id):
if request.method == 'GET':
old_obj = d.get_by_id(id)
form = MyObjForm(obj=old_obj)
return render_template('create.html', form=form, id=id)
else:
#never entry
pass
HTML 'create.html'
<form method="post" role="form">
{{ form.csrf }}
{{ macros.render_field(form.name) }}
{{ macros.render_field(form.minDescription) }}
{{ macros.render_field(form.descriptions) }}
<input class="btn special" type="submit" value="Save"/>
</form>
I try this:
<form method="post" role="form" action="{{ url_for('edit', id=id) }}">
and this:
class MyObjForm(Form):
id = StringField()
any not have a progress :(
Wath wrong?

I identified the problem:
If not use args ('obj=new_obj') when MyObjForm create the save button call my route in post mode as well
When i published the question too simplified the description of the problem. Realy MyObjForm include BooleanField:
class MyObjForm(Form):
name = StringField('name')
minDescription = StringField('minDescription')
descriptions = TextAreaField('descriptions')
isArchive = BooleanField('Is not public')
I didn't notice the checkbox stopped showing up on the form for reasons unknown to me. The standard rendering method was used for output:
{{ macros.render_field2(form.isArchive) }}
{% macro render_field2(field) %}
{{ field.label }}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% endif %}
{% endmacro %}
To solve the issue with the visualization applied the following:
<input type="checkbox" id="isArchive" name="isArchive">
<label for="isArchive">{{ form.isArchive.label }}</label>
{% for error in form.isArchive.errors %}
<li><font color="red">{{ error }}</font></li>
{% endfor %}
One last thing. Did not notice how, but the form also stopped working when you add an object, no longer pass validation. And the reason was {{ form.csrf }}} which had to be replaced with {{ form.csrf_token() }}. Still had to remove the validation parameters for BooleanField.
Now the problem is partially solved.I associate these issues with the installation of the flask-security component. Unfortunately, I was not able to make a normal display of the checkbox, but at least I can move on.
If anyone has any idea how these things can be related to each other or what I'm wrong please let me know. I do not want to leave gaps in knowledge.

Related

django: modelChoiceField form not working in template

I am confronted for the first time to a situation where I want the user to select model column values based on some constraint. The goal is to have the user select something and then output the result below the form on the same page.
I am not sure what I am doing wrong but submiting the form output:
Select a valid choice. That choice is not one of the available choices.
Here is what I have been able to do:
forms.py
class SelectBuildingForm(forms.Form):
filename = forms.ModelChoiceField(queryset=Building.objects.none())
def __init__(self, *args, **kwargs):
us = args[1] or None
forms.Form.__init__(self, *args, **kwargs)
self.fields['filename'].queryset = Building.objects.filter(project=us).values_list('filename',flat=True)
views.py
#login_required
#owner_required
def FileSelectionView(request,pk):
form = SelectBuildingForm(request.POST or None, pk)
# if form.is_valid():
# filename = form.cleaned_data('filename')
# print(filename)
# return redirect('comparator_test')
return render(request,'files_selection.html', {'form':form})
and template
<div class="mt-5 md:col-span-2 md:mt-0">
<form method="POST" id="my-form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" value="Select">GOOOO</button>
</form>
{% if form.is_valid %}
{% for choice in form.cleaned_data.choices %}
<p>{{ choice }}</p>
{% endfor %}
{% endif %}
</div>
I have tried a couple options to validate the selection but none of them work. Can a pair of fresh eyes see where I am messing up?

Python Flask forms not capturing form input

I am running the latest Flask, Python 3.10. The app is installed on a Windows IIS Server. I have three forms on a single page. There is one submit button. Each form has a unique ID.
When I fill out one or all of the forms and hit the Submit button there is a view Class handler for the POST request. It is being called but the form data is missing.
One of the form elements looks like the following; the other two are similar but without the render_submit_field call:
<form id="add_session_form" action="{{ url_for('session_api') }}" method="POST" novalidate
role="form">
{{ session_form.hidden_tag() }}
{% for field in session_form %}
{% if not field.flags.hidden %}
{% if field.type == 'BooleanField' %}
{{ render_checkbox_field(field, tabindex=loop.index * 300) }}
{% elif field.type == 'SelectField' or field.type == 'SelectMultipleField' %}
{{ render_select_field(field, tabindex=loop.index * 300) }}
{% elif field.type == 'SubmitField' %}
{{ render_submit_field(field, tabindex=loop.index * 300) }}
{% else %}
{{ render_field(field, tabindex=loop.index * 300) }}
{% endif %}
{% endif %}
{% endfor %}
</form>
The POST method of the view Class looks like:
#staticmethod
def post():
try:
db_session = db()
school_form = SchoolForm(obj=current_user)
class_form = ClassForm(obj=current_user)
session_form = SessionForm(obj=current_user)
school_list = SchoolAPI.get_all_schools()
if school_form.validate_on_submit():
# Copy form fields to user_profile fields
school = School()
school_form.populate_obj(school)
db_session.add(school)
db_session.commit()
school_form = SchoolForm()
if class_form.validate_on_submit():
class_ = Class()
class_form.populate_obj(class_)
db_session.add(class_)
db_session.commit()
classes_form = ClassForm()
if session_form.validate_on_submit():
session = Session()
session_form.populate_obj(session)
db_session.add(session)
db_session.commit()
session_form = ClassForm()
return render_template(
'main/user_page.html',
current_user=current_user,
school_form=school_form,
class_form=class_form,
session_form=session_form,
school_list=school_list
)
except Exception as e:
return Response(repr(e), status=HTTPStatus.BAD_REQUEST)
The curious part is that this was working at the beginning of 2022. I was pulled onto another project and have recently been put back on this one. I updated all dependencies and am not seeing any errors.
I am not sure what to check at this point.
Ideas?

Django Formset: object has no attribute 'get'

I think I'm almost there, but the last part just doesn't want to work :(. I hope you can help as I'm not seeing it anymore after 2 days.
Within my FormWizard I'm trying to (1) show a Formset based on a Slider Input in a previous set (setting the Extra value) and (2) in each Form within the Formset I want to show a ChoiceField (forms.Select) based on a Text-input in a previous step.
With a lot of searching on stackoverflow I am able to do step 1. Step 2 is almost working, except for the fact that the ChoiceField doesn't update with the new values from the Text-input. This is my code in views.py:
class FormWizardView(LoginRequiredMixin, SessionWizardView):
template_name = 'test/test.html'
def get_form_initial(self, step):
if step == 'formset_step':
form_class = self.form_list[step]
data = self.get_cleaned_data_for_step('slider_step')
if data is not None:
# To set the extra value in formset based on slider input
extra = data['number_slider']
form_class.extra = extra
# To set the ChoiceField value in formset based on text-input
form1_cleaned_data = self.get_cleaned_data_for_step('text_input_step')
formset = form_class().forms
for form in formset:
if form1_cleaned_data:
form.fields['text_input'].choices = [item for item in form1_cleaned_data.items()]
# Print form to test if the form updates
print(form)
return formset
return super(FormWizardView, self).get_form_initial(step)
def done(self, form_list, **kwargs):
do something
return something
I'm trying to return the formset, but I get the error 'TestForm' object has no attribute 'get'. I am probably returning the wrong thing here, but whatever I try to return, it doesn't work. Returning super(FormWizardView, self).get_form_initial(step) just gives me the empty ChoiceField and returning the form gives me the error object of type 'TestForm' has no len().
I also printed out the form in my console, and that seems to work properly. Does anyone know what I should return in order to get the populated ChoiceField?
Many thanks!
EDIT:
Thanks for your answer! When I modify my get_form:
def get_form(self, step=None, data=None, files=None):
if step == 'formset_step':
form_class = self.form_list[step]
data = self.get_cleaned_data_for_step('slider_step')
if data is not None:
# To set the extra value in formset based on slider input
extra = data['number_slider']
form_class.extra = extra
# To set the ChoiceField value in formset based on text-input
form1_cleaned_data = self.get_cleaned_data_for_step('text_input_step')
formset = form_class().forms
for form in formset:
if form1_cleaned_data:
form.fields['text_input'].choices = [item for item in form1_cleaned_data.items()]
# Print form to test if the form updates
print(form)
return super(FormWizardView, self).get_form(step, data, files)
I get the error ['ManagementForm data is missing or has been tampered with']. When browsing through StackOverflow it seems a template problem (and specifically not setting {{ wizard.management_form }}, but I took the plain code from the Django FormTools doc which should normally work. In my template I have this:
{% 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 %}
Am I not seeing something in the template or my get_form function not correct? Many thanks for looking at my problem :)
Method get_form_initial from form wizard should return a dictionary with initial data for the form that will be created, not the form itself. If you want to modify whole form, try modifying get_form method instead.

Django management form missing or tampered with - management form is in the template

I have a template with lots of forms on it, all wrapped in one form element. I have on MultiForm that is comprised of 4 regular forms, and two formsets. The formsets have been overridden to use custom formset classes.
I render the management forms in the templates, and can see the relevant info in the post.
For the formsets, I initialize the page with only one form visible.
When I try to submit the combined form I get the following error:
ManagementForm data is missing or has been tampered with
I have searched everywhere for the answer, and read about 15 posts on stack overflow with the same error, but none of the solutions seem to help.
The error page highlights the following line:
{{ beneficiaries.management_form }}
Template:
<form class='pension_form' id='implementation_form' action="{% url "confirmation_form" %}" method="post">
{% csrf_token %}
<ul>
{{ the_form.user_info.as_ul }}
</ul>
<ul>
{{ the_form.spouse_info.as_ul }}
</ul>
<div class='formset_container'> {{ children.management_form }}
{% for form in children %}
<div class='formset'><ul>{{ form.as_ul }} </ul><a class="glyphicon glyphicon-plus"></a></div>
{% endfor %}
</div>
<ul>
{{ the_form.employer_info.as_ul }}
</ul>
<ul>
<li>{{ the_form.beneficiary_general.WHO_BENEFITS }}</li>
</ul>
<div id='beneficiary_info_container' style='display:none;'>
<div class='formset_container'>
{{ beneficiaries.management_form }}
{% for form in beneficiaries %}
<div class='formset' >
<ul>{{ form.as_ul }}</ul><a class="glyphicon glyphicon-plus"></a></div>
{% endfor %}
</div>
<ul><li id='inheritance_order'>
{{ the_form.beneficiary_general.BENEFICIARIES_DIE.label_tag }}
{{ the_form.beneficiary_general.BENEFICIARIES_DIE }}
</li>
</ul>
</div>
<button class='btn btn-default main-btn'>{% trans "_Continue" %}
</form>
View:
def show_confirmation_form(request):
ChildFormSet = formset_factory(ChildInfo, formset=ChildInfoFormSet,
extra=14, can_delete=True)
BeneficiaryFormSet = formset_factory(BeneficiaryInfo, formset=BeneficiaryInfoFormSet,
extra=10, can_delete=True)
multi_form_prefix = 'main_form'
child_prefix = 'children_info'
beneficiary_prefix = 'beneficiary_info'
if request.method == 'POST':
form = ConfirmationForm(request.POST, prefix=multi_form_prefix)
children_forms = ChildFormSet(request.POST, prefix=child_prefix)
beneficary_forms = BeneficiaryFormSet(request.POST,
prefix=beneficiary_prefix)
if form.is_valid():
#not ready yet
return HttpResponseRedirect('/thanks/')
else:
form = ConfirmationForm(prefix=multi_form_prefix)
children_forms = ChildFormSet(prefix=child_prefix)
beneficary_forms = BeneficiaryFormSet(prefix=beneficiary_prefix)
context = {'the_form' : form, 'children' : children_forms,
'beneficiaries' : beneficary_forms}
return render(request, "confirmation_form.html", context)
Forms.py
class BeneficiaryInfo(forms.Form):
SHEM_PRATI_MUTAV = forms.CharField(label=_("First_Name"))
SHEM_MISHPACHA_MUTAV = forms.CharField(label=_("Last_Name"))
MISPAR_ZEHUT_MUTAV = forms.IntegerField(label=_("Mispar_Zehut"))
ACHUZ_HALUKA = forms.IntegerField(label=_("Percent_Allocate"))
class BeneficiaryInfoFormSet(BaseFormSet):
def clean(self):
"""
Adds validation to check that no two links have the same anchor or URL
and that all links have both an anchor and URL.
"""
if any(self.errors):
return
teudot_zehut = []
distribution_total = 0
for form in self.forms:
if form.cleaned_data:
teudat_zehut = form.cleaned_data['MISPAR_ZEHUT_MUTAV']
#allow empty forms.
if teudat_zehut:
if teudat_zehut in teudot_zehut:
form.add_error(None, 'No mutavim can share teudot_zehut')
distribution_total += int(form.cleaned_data['ACHUZ_HALUKA'])
if distribution_total != 100:
form.add_error(None, 'Distribution Total must be 100')
In case someone runs into a similar problem:
The problem was the I only showed the formsets if a certain checkbox was checked, and the management form was in the hidden area. I moved it out of the div that was hidden and it worked perfectly.

Submitting multiple forms in Django

I'm not sure if i'm going about this completely the wrong way, but in my html template i have a for loop that i want to present multiple forms, and one submit button to submit the data from all forms:
{% for i in Attribute_list %}
<form action="/Project/create/" method=post>{% csrf_token %}
{{ i }}:
<input type=text name={{ i }}><br>
<hr>
{% endfor %}
<input type=submit>
The problem with this is it only submits the last form.
The other problem i'm running into is getting the data back from the view. Since i'm naming the form the variable "i", i don't know how to "get" this data in my views.py:
def create_config(request):
if request.method == 'POST':
data_list = []
for data in request.POST.getlist():
data_list.append(data)
can You check this?
<form action="/Project/create/" method="post">
{% csrf_token %}
{% for i in Attribute_list %}
{{ i }}: <input type="text" name="{{ i }}"><br>
<hr>
{% endfor %}
<input type="submit">
</form>
As I understand without JS regardless how many forms You create only one POST request will be made.
In oyur example HTML is not valid so It can behave different ways in different browsers. But as soon as You have not closed form last one should be submitted.
As for second part
def create_config(request):
if request.method == 'POST':
data_list = []
for data in request.POST.getlist():
data_list.append(data)
I think You should use your Attribute_list. Or You can just iterate over all `POST' variables obtained.
def create_config(request):
if request.method == 'POST':
data_list = []
for key in request.POST:
data_list.append(request.POST[key]) # or .extend(request.POST.getlist(key)

Categories