Views and Templating in Flask with persisted, dynamic forms - python

I'm working on a UI flow that uses several stages of dynamic wtforms constructed from previous form choices and a backend datamodel (as per this). My current (novice) approach simply renders each new form in place of the previously submitted form. However, I would like to be able to persist the previous forms and their choices with each new submission so that the overall structure is visible.
Is there a flask pattern for accomplishing this?

In case anyone needs this in the future, I found the best way to do this was simply to persist the actual model data once the form had been submitted to a cookie via the flask session object, this way each new form / template stage could be a child of the last and the form / view and previous forms could be re-rendered using the data in the session cookie.

Related

How to have single form on multiple pages

I am looking for ways to best handle a single form on multiple pages. Like how a newsletter signup might be on a home page, an about page, and several blog pages.
I've handled this exact scenario in these 2 ways.
Write an API (using DRF) that takes a POST request, and then point the normal HTML form at that API. This works, and is very flexible, but feels like overkill.
Pass the form object into the context of each view I want the form to be on, and then include that into the template with includes form_snippet with form=form
The first approach is more flexible with wagtail, wherein all that needs to happen on the admin side is an inclusion of the newsletter as a snippet, where the admin user is able to choose if they want the newsletter on the page or not.
While both approaches work just fine, neither of them "feels" right, as I would think there is a simple way to do this without creating a big API, or passing around the form object to every single view.
three years later on you probably found an answer.
For documentation purposes and Google searchers, Wagtail offers an explanation on how to make a multiple step form here:
https://docs.wagtail.org/en/v3.0.1/reference/contrib/forms/customisation.html#multi-step-form
I did this with a contact formular. I handled it with a new app for my contact formular.
In this contactApp is the templates/contactForm.html. To include this contactForm where I want I use {% include 'contact/contactForm.html' %} so it loads the contactForm.html from my app called contact.

Is there pyramid package for storing form related information serverside (avoid mirroring hidden fields)?

Background: I'm currently creating a project in pyramid. It uses beaker sessions and SQLAlchemy as DB-backend.
Some forms contain information in hidden fields, with the only purpose of supplying it to the view that processes the post, the user never sees them and doesn't need to. An example:
A DB-entity can be edited by the user. Since all data fields of the entity, including the name, can be edited, the ID of the entity is put in a hidden field, so the view can query the object and update it. This approach has some flaws:
The ID of my entities is no concern of my users. They should not even be aware of it.
Data being resubmitted by the client can be tinkered with. Someone might try to get access to other entities by forging a different id here.
In other scenarios there could be more mirrored data than just an id (maybe the return to url? Maybe much more somewhere). Using hidden fields for that would transmit the data to the client and back, needlessly (bandwidth) and makes it necessary to validate it.
Transmitting data over insecure channels (the client) without need is just wrong. The solution is not that complicated: store that information on the server (in session or DB), and make it accessible with a key (form-id?), similar to a session, with a session-id. Put that totally anonymous token into a hidden field. That will be the only hidden field needed in the form. Everything else would be stored on the server and be restored from the view responding to the post-request (well - I would still have my CSRF-token in there, because it's in all my post requests). This would also make it easy, to give forms a timeout, since you can make the form-id expire after some hours or so.
If I recall correctly, drupals does supply like this by default. I would not really expect pyramid itself to have support for this, but would imagine there must be a package doing this, using the pyramid supplied session object, still could not find any. I'm sure I could write something usable myself, but why do so if there might be something awesome out there already?
Anyone knows of such packages?
If I understand you, you want to update a model without using hidden fields on forms.
Here is how to do it
Using pyramid_simpleform and Urldispatch
#view_config(route_name="my_route",renderer="myrenderer.mako")
def update(request):
id = request.matchdict['id']
#assuming you have an SQLalchemy model called MyModel which you imported
#your model has a method that gets by id
toupdate = MyModel.get_by_id(id)
form = Form(request, schema=MyModelSchema,obj=toupdate)
if not toupdate:
#you can flash a message here and redirect wherever you want
return HTTPFound(location=request.route_url('home'))
if 'submit' in request.POST and form.validate():
form.bind(toupdate)
DBSession.add(toupdate)
DBSession.flush()
#redirect
return HTTPFound(location=request.route_url('home'))
return dict(form=FormRenderer(form))
At the view, just draw your form fields without any hidden field using the form object.
#configure your route as below
config.add_route('my_route','/myroute/{id}/edit')
UPDATE
to use webhelpers tool. Follow as bellow(Using Mako template)
<%
from webhelpers.html.tools import js_obfuscate
%>
js_obfuscate("<input type='hidden' name='check' value='valid' />")
to obfuscate the data in javascript tag

Django : Storing user steps with django admin form

I am doing a workflow app that forces the users to go through a set of forms and save some data.
They can leave the process of filling that form and log-out at any point of time.
When they log in back, they should be redirected to the same form/page where they left last time.
What is the best way to approach this problem ? Should I have a model in this app which stores such data every step ?
UPDATE:
By form I mean admin forms.
Django form wizard is what you want.
You can use SessionWizardView for more easily display the wizard when user comes back again.

Multiple forms in one page in DJANGO

I've been developing a django project for 1 month. So I'm new at Django. My current problem with Django is; When I have multiple forms in one page and the page is submitted for a form, the other forms field values are lost. Because they are not posted.
I've found a solution for this problem;
When there is get method, I send the other forms value with the page url and I can handle them from the get request.
When there is post method, I keep the others form fields value in
hidden inputs in HTML side in the form which is posted. Hence I
can handle it from the post request.
Maybe I can keep them in session object. But it may not be good to keep them for whole time which the user logg in. But I dont know. I may have to use this method.
Is there another way which is more effective to keep all forms fields in Django?
Any Suggestion?
Thank!
You can make use of AJAX for a single form submission instead of whole page submit.

POSTing data to a django admin form

I'm writing a Django app whose data will be coming from different sources, including Excel spreadsheets. I've written some code to do an initial import from those sheets, but I don't like the idea to re-import the whole data each time a row is added - and my client does not want to re-type the data himself.
A possible solution would be to add a form with a simple textarea where the user could copy-paste a whole line of the spreadsheet. Then a view could split the data, pre-process it and post it to the standard admin form for the corresponding object.
Ideally, it would behave like the user has really posted from this form: if the data validates, the object is created and if not, the (admin) form is re-displayed with the nice red error boxes.
So I thought I would just need something like
from django.shortcuts import redirect
[...]
return redirect(to, method=POST, *args)
but it doesn't seem to be available.
I also thought of passing the data as a big query string like http://.../admin/app/object/add/?ID=1234&name=toto&... but my model has many fields, with one-to-many and many-to-many inlines, possibly long textfields, etc. so this approach seems like more trouble than necessary.
Any idea how to obtain something like a POST redirect? or another approach to this problem?
If you're already writing code that is specific to your form, why not create the objects in that same function instead of trying to fake a POST request to the admin site?
To me, it sounds more difficult to use the default admin form than to use your existing pre-processing view to start creating or updating objects.
I'd just hook up your pre-processing view to your ModelAdmin definition via the get_urls method, set up a template that could be as simple as
<form action="." method="post">
<textarea name="data"></textarea>
<input type="submit" value="submit" />
</form>
and manually process the data in the input form request.POST.get('data', '').split(',') (or what have you) and start populating your models.
When done, send a message and redirect back to your app view or changelist view.
request.user.message_set.create(message="Finished populating X models")
return http.HttpResponseRedirect('../')
For this, you should step away from the built-in admin interface.
Create your own ModelForm http://docs.djangoproject.com/en/dev/topics/forms/modelforms/
Create your own view functions that does validation and POST.
This should probably be a 2-step transaction.
view_function_1
if method is GET, present the empty form.
if method is POST, they have pasted a value into the text box and filled in the "other" fields.
Parse the data in the text box.
For fields which are empty, fill in the missing values from the text box.
Put the form's data into the session.
Do a redirect to a URL that will move to view_function_2
view_function_2
If the method is GET, fetch the form data from the session, fill things in and
present the form with data.
If the method is POST, validate and save the results.
redirect to a page which will display the details to the user.

Categories