WTForms add additional categories to SelectField - python

I've seen forms like this on the internet before - basically I want to allow the user to dynamically add fields to a SelectField dropdown form in WTForms. For example, maybe the first field in the dropdown menu is a link that allows the user to add custom fields to the form. How would I go about implementing something like this in WTForms? Thanks!

Hi Michael I know this is 3 months late but I recently did something similar with the help of AngularJS and bootstrap modals so I thought I'll put this up for the sake of completeness:
This is a very simplified version I have not included error checking or validation of any sorts you of course want to do that for your production environment.
In my template the following is what the select field looks like. Instead of the first option being the one to enable a person to create something I just added a link next to the select field that allows a person to add a new category. The link itself opens up a form in a modal.
The following is the select field:
<div class="form-group">
{{ form.maincategory.label(class="col-sm-2 control-label") }}
<div class="col-sm-5">
{{ form.maincategory(**{'ng-model':'maincategory',
'ng-options':'c.id as c.displayname for c in allmaincategories',
'class':'form-control'}) }}
#over here is the link that opens the form in a modal window
</div><a data-toggle="modal" href="#newcategory">Add a new category</a>
</div>
When a user click on the link add new category the following modal window loads:
<!-- Add new category Modal -->
<div class="modal fade" id="newcategory" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Create new main category</h4>
</div>
<div class="modal-body">
<form method="post" ng-submit="createCategory()">
<div class="form-group">
{{ categoryform.displayname.label(class="col-sm-8 control-label") }}
<div>
{{ categoryform.displayname(**{'ng-model':'maincat.displayname','class':'form-control'}) }}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Save changes" />
</div>
</form>
</div>
</div>
</div>
</div>
The WTFORM form class that renders the above form in the modal window is as follows:
class DirectoryMainCategoryForm(Form):
displayname = TextField('Category name as it appears', validators=[DataRequired(message=(u'This category name is how it appears in the menu'))])
#the following is the form main form where the select appears
class MainEntry(Form):
maincategory = QuerySelectField('Main category', validators = DataRequired(message=(u'Please select a category for this place'))], get_label='category',
allow_blank=False, query_factory=Maincategory.query.all,blank_text =('-- Select a main category --'))
#And of course the javascript magic that glues it all together:
function DirectoryController($scope, $http){
#Adds a new category to the select menu
$scope.createCategory = function() {
var categorydata = angular.toJson($scope.maincat);
$http.post('/create/new/category', categorydata).success(function(data) {
$scope.allmaincategories = data.category;
});
}
}

Related

how to get data from database to modal form?

I am using Flask, Jinja2, Python and SQLAchemy.
I want to retrieve data from my database and display it on my modal.
This is my html code:
{% extends "layout.html" %}
{% block title %}
Admin
{% endblock %}
{% block body %}
<h1> Admin</h1>
<div class="form-group">
<table border=1>
<tr>
<th>usa_order_id</th>
<th>user_id</th>
<th>product_name</th>
<th>cpu</th>
</tr>
{% for usa_order in usa_orders %}
<tr>
<th>{{usa_order.usa_order_id}}</th>
<th>{{usa_order.user_id}}</th>
<th>{{usa_order.product_name}}</th>
<th>{{usa_order.cpu}}</th>
<th>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
Open modal
</button>
<!-- The Modal -->
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" >×</button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="form-group">
<input class="form-control" name ="usa_order_id" value={{usa_order.usa_order_id}}>
<input class="form-control" name ="user_id" value={{usa_order.user_id}}>
<input class="form-control" name ="cpu" value={{usa_order.cpu}}>
</div>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</th>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
When I click to open modal, I want it to display the data from my database. I tried some other quick solutions but none of them seem to applicable in Python.
Question is: How can I retrieve data from my db table and display it on the modal - which generated in a for loop?
here is my python, just show all the db
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from model import *
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='mysql://root:xxx#localhost:3306/xxx'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']=True
db = SQLAlchemy(app)
#app.route("/admin")
def index():
usa_order = usa_order.query.all()
return render_template("admin.html",usa_order = usa_order)
Since you didn't provide snippets belong to your routes.py, I will have to assume that you are passing the usa_orders data to template without a mistake.
If you want to generate a modal for each usa_order in usa_orders then you would need to create unique modals for each order. Otherwise, you will end up displaying the same modal for many different users/orders. To achieve this, you simply need to provide a unique id for modal, by editing following line:
<!-- The Modal -->
<div class="modal" id="myModal">
To something like:
<!-- The Modal -->
<div class="modal" id={{usa_order.usa_order_id}}>
Or any other unique non-repeating value - preferably from your db.
Let me know if this helps, and if it doesn't work for you: please provide more information on what kind of error(s) you are getting.

WTForms TextAreaField DataRequired not raising validation error in Bootstrap modal

I have a very small form in a bootstrap modal including just two fields: a TextAreaField and a Submit button. My TextAreField is DataRequired.
On top of that this field uses CKEditor (similar to quillsJS) to make the text area WYSIWYG.
Problem is that the form submits even when no data has been entered, and reloads the parent page.
I would very much like to know how to prevent that form submission and raise the validation error when no data has been entered.
I would like to get WTForm validation and not the browser's (which anyway doesn't work either for this case).
I should also mention, in case it matters, that my modal is a partial file (jinja).
My trigger for the modal is this, living in perfume-cursor.html
Edit
And this is my modal (in a partial file perfume-modals.html)
<div class="modal fade" id="reviewPerfumeModal" tabindex="-1" role="dialog" aria-labelledby="reviewPerfumeModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteUserModal">Please Leave a Review</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form method=POST action="{{ url_for('reviews.review_perfume', perfume_id=perfume._id) }}" id="form-review">
<fieldset class="form-group">
<div class="form-group">
{{ form.review(class="form-control form-control-md", placeholder="Review", id="description") }}
</div>
</fieldset>
<div class="modal-footer">
<div class="form-group">
{{ form.submit(class="btn btn-primary") }}
</div>
</div>
</form>
</div>
</div>
</div>
</div>
The id="description" is what CKEditor uses to render that text area field as a WYSIWYG editor, btw.
I would really appreciate a lot any help on this!!
Thanks in advance!
Update:
In case it helps this is my form class, although I'm pretty sure the issue is modal related and not WTF related:
class AddReviewForm(FlaskForm):
review = TextAreaField("Review", validators=[DataRequired()])
submit = SubmitField("Post Review")

How to use a Bootstrap Modal to delete a object using Class Based Views in Django?

I´m using CBV in Django to delete items. What I want to do is when I click the button to remove, instead of redirecting me to the post_confirm_delete view I want to pop up a modal in which I show the question if the user want to delete the object and a button for confirm and the other to delete the object. I have tried this in the HTML:
<button class="btn" data-toggle="modal" data-target="#fm-modal-grid">Delete</button>
<div class="modal fade" id="fm-modal-grid" tabindex="-1"
role="dialog" aria-labelledBy="fm-modal-grid"
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" aria-label="Cerrar">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-sm-6">
<p>Are you sure you want to delte {{post.title}}</p>
</div>
</div>
</div>
</div>
<div class="modal-footer">
Delete
<button class="btn btn-primary" data-dismiss="modal">Cancelar</button>
</div>
</div>
</div>
</div>
And I have this in the delte CBV in the views class:
class PostDeleteView(DeleteView, LoginRequiredMixin):
model = Post
success_url = reverse_lazy('post_list')
template_name = 'blog/post_list.html'
And the url file looks like this:
urlpatterns = [
path('',views.PostListView.as_view(),name='post_list'),
path('article/', views.ArticleView.as_view(), name="article"),
path('newpost/', views.CreatPostView.as_view(), name="new_post"),
path('post/<int:pk>', views.PostDetailView.as_view(), name='post_detail'),
path('post/<int:pk>/edit/', views.PostUpdateView.as_view(), name='post_edit'),
path('post/<int:pk>/remove/', views.PostDeleteView.as_view(), name='post_remove'),
]
When I press the Delete button inside the modal, it redirect me to my index, but doesn't delete the object. How can I do this?
By the docs
The given object will only be deleted if the request method is POST.
So the link was the reason that it did not work. I solved it by putting the modal button for delete inside a form like this:
<form action="{% url 'blog:post_remove' pk=post.pk %}" method="POST">
{% csrf_token %}
<button class="btn">Delete</button>
</form>
Indeed you need to put your button inside a form to make a POST.
The other solution is to trigger the modal using some JS, and then when you confirm the deletion you can make an Ajax call of type POST. So you are not obligated to put the button inside a form.
$.confirm({
title: 'Deletion pop-up',
content: 'Do you want to proceed ?',
buttons: {
confirm: function () {
$.ajax({...}),
success: function(response){...},
}
}
)};

How to fix modals not showing?

I have a series of 6 modals that are created through a flask/jinja2 frame work loop and 1 modal that is an example outside of the loop. The modals all populate and populate correctly when looking at the page source. The example modal that is outside the loop shows without issue, however the other 6 modals will not fire.
https://www.sfiltrowani.pl/filter_instructions is the live site with the problem.
https://github.com/rscales02/sfiltrowani is the full code git repository.
This is for a flask app run on AWS elastic beanstalk. I was able to get the example modal to show by defining modal id and data target manually, those were the only changes I made from a copy/paste of the original modal code and original link to modals.
example link identical links from A-F
{{ _('(instrukcja photo F)') }}
modal loop to create image modals for instructions
{% for image in images %}
<!-- Modal -->
<div class="modal fade" id="{{ image }}" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<img id='modal-img' src="{{ url_for('static', filename='images/instructions/' + image) }}" alt="{{ loop.index }}">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% endfor %}
Expected results a modal that fires for each photo in my instructions. Current results only example modal will show.
[Edit]
I am new to the stack, edited to show the 3 lines of code that were hidden, due to lack of indentation. Thanks and sorry!
Your link does not point to the modal to show .
The modal needs an ID that is referenced by data-target
{{ _('(instrukcja photo F)') }}
<div class="modal-dialog" id="this-modal-id">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<img id='modal-img' src="{{ url_for('static', filename='images/instructions/' + image) }}" alt="{{ loop.index }}">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
I fixed it! It would appear that modal id's are sensitive to specific formatting and not just random strings. Previous version that did not work had id and data-targets of 'instrukcja*.jpg' when '.jpg' was removed, the modals function perfectly.

Handle POST/GET forms with Django and Bootstrap Modal

I'm using different forms (POST and GET) in my Django web application and Bootstrap modal to do that.
In my template, user can choose some documents, submit the list of documents which is picked up to a Django form (CustomerForm) in my modal. This CustomerForm lets to send an email with user informations previously filled.
My CustomerForm looks like this :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by('name')
self.fields['email'].required = True
self.fields['first_name'].required = True
self.fields['last_name'].required = True
self.fields['country'].required = True
self.fields['institution'].required = False
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
I have views.py file :
class HomeView(CreateView, FormView):
""" Render the home page """
template_name = 'index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
# display some things
# ...
if "DocumentSelected" in self.request.GET:
checkbox_list = self.request.GET.getlist('DocumentChoice')
document = Document.objects.filter(id__in=checkbox_list)
kwargs['selected_document'] = document
return super(HomeView, self).get_context_data(**kwargs)
def form_valid(self, form):
email = form.cleaned_data['email']
country = form.cleaned_data['country']
for checkbox in self.request.GET.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email)
now = timezone.now()
expiration = now + settings.DOWNLOAD_VALIDITY
Download.objects.create(email=email, country=country, doc_id=checkbox, token=token,
expiration_date=expiration)
self.send_email(email, document.upload, document.publication.title, token)
return super(HomeView, self).form_valid(form)
And finally in my HTML template you can find something which looks like this :
<form method="GET" action="">
<!-- Table with checkboxes - User has to check wanted objects -->
<div class="row">
<div class="col-md-offset-3 col-md-4">
<input type="submit" class="btn btn-default" name="DocumentSelected" value="{% trans 'Save document(s)' %}"/>
<input type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" value="{% trans 'Send document(s)' %}"/>
</div>
</div>
</form>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">{% trans 'Your informations' %}</h4>
</div>
<form method="post" action="" novalidate>
{% csrf_token %}
<div class="modal-body">
<div class="row">
<div class="col-md-12">
{{ form.email|as_crispy_field }}
</div>
</div>
<div class="row">
<div class="col-md-6">
{{ form.first_name|as_crispy_field }}
</div>
<div class="col-md-6">
{{ form.last_name|as_crispy_field }}
</div>
</div>
<div class="row">
<div class="col-md-6">
{{ form.country|as_crispy_field }}
</div>
<div class="col-md-6">
{{ form.institution|as_crispy_field }}
</div>
</div>
</div>
<div class="modal-header">
<h4 class="modal-title">{% trans 'Your cart' %}</h4>
</div>
<div class="model-body">
{% for element in selected_document|dictsort:'format' %}
<!-- Display wanted objects -->
{% endfor %}
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-default" data-dismiss="modal" value="{% trans 'Send' %}"/>
</div>
</form>
</div>
</div>
</div>
Process :
This is the needed way :
User has to check one or multiple documents
User submits the choice and a modal containing CustomerForm is opening.
User fills CustomerForm fields and see in Cart part his document(s)
User submits the CustomerForm and an email is sent with previous informations/documents.
I think my method could work, but I don't overcome to call form_valid function and I would like to write correctly this class.
There is certainly ugly issues and I apologize by advance. But this is not the best way to improve myself and doesn't reproduce these issues ? ;)
Thanks !
EDIT :
I made something which seems to work. I removed data-dismiss="modal" from my modal submit button. I read that this attribute closed my modal and didn't post any form !
Finally, is it a good way to do what I did ?
Is it possible to replace both buttons Save documents and Send documents by an unique button which get documents and open the modal ?
I made something which seems to work. I removed data-dismiss="modal" from my modal submit button.
Previously :
<input type="submit" class="btn btn-default" data-dismiss="modal" value="{% trans 'Send' %}"/>
Now :
<input type="submit" class="btn btn-default" value="{% trans 'Send' %}"/>
It works now !
It was because data-dismiss="modal" closed the modal and I didn't know that.

Categories

Resources