Disabling boolean fields in Flask WTForms - python

I know this is possible (because I have done it before!) but I cant find the correct syntax anywhere on the web including in the WTForms manual and in posts on here.
I want to disable a boolean field in a form.
In the template I have tried to add (disabled = "disabled") and (disabled = True) e.g.
<div class="col-md-6">{{ wtf.form_field(form.news)(disabled="disabled")}}</div>
and...
<div class="col-md-6">{{ wtf.form_field(form.news(disabled="disabled"))}}</div>
In the form definition in my Python code I have tried to add disabled = True e.g.
news = BooleanField(label=u"Search news", description="description", validators=[], disabled = True)
Every way I have tried throws an error.

The field would be called with disabled to the form field. Here's some example code:
import wtforms
class MyForm(wtforms.Form):
my_field = wtforms.StringField()
f = MyForm()
print(f.my_field(disabled='disabled').__html__())
Output:
<input disabled="disabled" id="my_field" name="my_field" type="text" value="">
If that's not working for you, I suspect the definition of wtf.form_field is perhaps at fault. I assume that's a macro you have.

Related

How to display a dropdown list in Django form?

I have an issue with the display of a dropdown list, which is a field part of a Django form. Instead of a normal dropdown list, it appears like a kind of multiple select choice box (at least, it's high as this kind of object, as you will see in below screenshots), with the feature of a dropdown (the small arrow that opens the choice list).
I do not understand why it looks like this and how to solve this.
Edit
I pushed my current version into production, for tests and demo purposes, and surprisingly, it works, the dropdown displays properly (and still ugly in local environment)
If anyone has an explanation/solution for that, he is welcome
As far as possible I use standard objects (I'm not very comfortable with CSS) and, in this case, I did not manage to update anything (event setting height had no impact, maybe there is something wrong in this part too)
And I can understand my question is not perfect, but please explain me what's wrong to allow me to add missing information (and I still do not understand why we cannot thanks in advance people who will read and try to solve problems here, but it's another question... that will probably be edited without any explanation or comment)
Related model field is defined like this:
class Company(models.Model):
"""
Company informations
- Detailed information for display purposes in the application
but also used in documents built and sent by the application
- Mail information to be able to send emails
"""
company_name = models.CharField("nom", max_length=200)
comp_slug = models.SlugField("slug")
rules = [("MAJ", "Majorité"), ("PROP", "Proportionnelle")] # Default management rule
rule = models.CharField(
"mode de scrutin", max_length=5, choices=rules, default="MAJ"
)
The form has no dedicated rules, even if tried to add some (kept as comment in the code below):
class CompanyForm(forms.ModelForm):
company_name = forms.CharField(label="Société", disabled=True)
# rules = [("MAJ", "Majorité"), ("PROP", "Proportionnelle")]
# rule = forms.ChoiceField(label="Mode de scrutin", choices=rules)
class Meta:
model = Company
exclude = []
Here is the view:
#user_passes_test(lambda u: u.is_superuser or u.usercomp.is_admin)
def adm_options(request, comp_slug):
'''
Manage Company options
'''
company = Company.get_company(comp_slug)
comp_form = CompanyForm(request.POST or None, instance=company)
if request.method == "POST":
if comp_form.is_valid():
comp_form.save()
return render(request, "polls/adm_options.html", locals())
And the part of HTML code:
<div class="row border mt-4">
<div class="col-sm-12">
<h5>Préférences de l'application</h5>
<div class="row">
<div class="col-sm-5 mt-2">
{{comp_form.use_groups}} <label for="{{comp_form.use_groups.label}}">{{comp_form.use_groups.label}}
</div>
<div class="col-sm-7 mt-2">
<p><label for="{{comp_form.rule.label}}">{{comp_form.rule.label}}</label> : {{comp_form.rule}}</p>
<p>{{comp_form.upd_rule}} <label for="{{comp_form.use_groups.label}}">{{comp_form.upd_rule.label}}</p>
</div>
</div>
</div>
</div>
The concern is the format of the field:
When the user click on the arrow, here is the display (there are only 2 options):
What did I wrong?
How can I change this (in views or HTML/CSS)?
In your Company model you have only used two choices:
rules = [("MAJ", "Majorité"), ("PROP", "Proportionnelle")]
When rendering this model form in HTML there should be only two options. If you want may options you should modify your model.

Django ModelForm's DateTime value being localized/translated with localization turned off

So I'm working on this Activity management platform, we are using Django 3.0.4. Before I expose my problem, I must say that I'm somewhat new to Django and python itself.
My current objetive is to allow the administrator to set specific dates for specific events. Initially the page must show the current dates and details. That I can already the do with the code shown below
This is an example of the model used to store the dates
class Dates(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
datestart = models.DateTimeField(db_column='DateStart')
dateend = models.DateTimeField(db_column='DateEnd')
class Meta:
db_table = 'Dates'
This is my form
class dateForm(forms.ModelForm):
class Meta:
model = Dates
exclude = ['id']
And this is my current view function
def editdates(request):
dates_current = Dates.objects.get(id=1)
dates_form = dateForm(instance=dates_current)
if request.method == 'POST':
submitted_data = request.POST.copy() #Might need to change incoming data before saving to db
dates_form = diaAbertoSettingsForm(submitted_data, instance=dates_current) #Generate form with existing data
if dates_form.is_valid():
dates_form.save()
return render(request=request,
template_name = 'dates/edit.html',
context = {'form': dates_form})
The same page that shows the data (dates) must also allow you to submit a change, this would be relatively easy to do. The real problem starts when I want to submit the form.
Currently, I do the following to display the current values
<div class="column">
<div class="field">
{% if form.datestart.errors %}
<div class="alert alert-danger">
<strong>{{form.datestart.errors}}</strong>
</div>
{% endif %}
<label class="label">Date Start</label>
<div class="control">
<input class="input" type="text" name="datestart" value='{{form.datestart.value}}'>
</div>
</div>
</div>
Which is all fine, until you see that the result from {{form.datestart.value}} is not a normal "YY-MM-DD H:M:S" dateTime (e.g. 2000-01-01 00:00:00) format like you'd expect, but a "Written out" format like "Jan. 1, 2000, midnight" which obviously causes problems when I want the user to edit this date. If they were to keep the format, the form would return an error saying the format of the dateTime is invalid.
To fix this problem I've tried the following:
Turning off "Format Localization" in settings.py and on a template by template basis
Turning off "Translation", same as above
I've tried using the date filters described in the django documentation
I've also tried using the datetime parser from django utils
I've also looked around on other sources besides the documentation but none seem to share my problem.
If I were to place {{form.datestart}} instead of {{form.datestart.value}}, would indeed make it come out correct, but since I want to use a classes from bulma, I don't see a way around it.
How can I make it so the {{form.datestart.value}} comes out as 2000-01-01 00:00:00 and not as Jan. 1, 2000, midnight ?
This is only an example, the real model has about 10 diferent start/end dates, so a way to keep automated it, would be ideal but not required.
I fixed it. The solution was rather easy and in hindsight It's what I should've done in the beginning.
First of all, I turned off localization globally. Secondly I changed my modelForm to the following
class dateForm(forms.ModelForm):
class Meta:
model = Dates
exclude = ['id']
widgets = {
'datestart': DateTimeInput(attrs={'class': 'input'})
}
This allowed me to give custom classes to my fields. Then in the template I replaced <input class="input" type="text" name="datestart" value='{{form.datestart.value}}'> with the complete field {{form.datestart}}.

Add editable choices in django

I am trying to add a editable choicefield in django like the picture, already do some research on this. Unfortunately, the solution like django-autocomplete doesn't quite fulfill my needs. The autocomplete looks fine, but if do so, I need create a django modal to generate the choices through a url view request, but in my case, it doesn't necessary to do that, I just need put these 3 choices for ip address in the dropdown list, and choose one of them then edit it or submit.
The solutions I found, but they are not very well fit my need:
Django admin: Change selected box of related fields to autocomplete
Django editable dropdown field
If you want to use just those three entries the quickest way is to use a datalist, it just needs to be added into your HTML somewhere.
<div id="page-wrapper">
<label for="ip">Network address</label>
<input type="text" id="ip" list="ip-datalist">
<datalist id="ip-datalist">
<option>192.168.0.0/24</option>
<option>10.0.0.0/24</option>
<option>172.16.0.0/24</option>
</datalist>
</div>
If your options are likely to never change, you could hardcode them into your html like the answer above. If you're generating your dropdown using a form however it would be better to do something like this:
class MyForm(forms.Form):
ip_list = ((1, '192.168.0.0/24'), (2, '10.0.0.0/24'),
(3, '172.16.0.0/24'), )
network_address = forms.ChoiceField(label='Network Address',
choices=ip_list)
...
Once you render the form object in your template it ends up producing html like this:
<label for="id_network_address">Network Address:</label>
<select id="id_network_address" name="network_address">
<option value="1">192.168.0.0/24</option>
<option value="2">10.0.0.0/24</option>
<option value="3">172.16.0.0/24</option>
</select>
This way it is easier to change the ip_list in future if you need to, plus its keeps all your code in one place. This is explained in the docs here.

How to use hidden input in an html form with Python+Jinja2

When I put this line in my html template, I can successfully pass the input string via a jinja2 variable into my Python code...
<label for="firstName">First name*</label>
<input type="text" name="fname" id="firstName" value="{{ fname }}">
However, when I attempt to pass a hidden input with the following line...
<input type="hidden" name ="contact_form" value="{{ active_form }}">
... I'm not seeing the value pass back to my Python code. I've not learned Javascript yet. Is there some Javascript required to pass hidden input values? What am I missing?
I recommend using WTForms.
Example
from wtforms import TextField, validators, PasswordField, TextAreaField, HiddenField
class ArticleCreateForm(Form):
title = TextField('Title', [validators.Required("Please enter title.")],
filters=[strip_filter] )
body = TextAreaField('Body', [validators.Required("Please enter body.")],
filters=[strip_filter])
category = QuerySelectField('Category', query_factory=category_choice )
person_name = HiddenField()
views.py
#app.route('/create', methods=['GET', 'POST'])
def article_create():
if 'email' not in session:
return redirect(url_for('signin'))
person = Person.query.filter_by(email=session['email']).first()
name = person.firstname
article = Article()
form = ArticleCreateForm()
form.person_name.data = person.firstname
if form.validate_on_submit():
form.populate_obj(article)
db.session.add(article)
db.session.commit()
return redirect(url_for('index'))
return render_template('create.html', form=form, person=person, name=name)
I know this is an old post but I was fooling around with a Jinja template and I wanted solve this particular issue since I was dealing with it myself. I was planning on fooling Jinja by passing in my value and adding the quote symbols (") in a concatenated string along with my Jinja variable (named "ticket_number") like so:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number + '"' }}>
That will NOT work. So I removed the concatenation and passed the variable in directly. This seemed promising. Was expecting to find the HTML code would contain the variable value without the quote symbols surrounding up but was presently surprised to find that either Jinja or Flask quoted the variable correctly with no extra add on's using the straight variable value:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number }}>
The variable itself is an integer so I confirmed if this also happens with regular alphanumerical string variables. Let me know if it works for you all-
If you are using Flask along with Jinja2 (which I would recommend), you can run code like this in the view function:
from flask import request
#app.route('/path/to/submit/page', methods=["GET","POST"])
def viewfunctionforsubmitpage():
request.form['contact_form']
Flask is a nice, lightweight, and built using Jinja2, so that is good.

Display html form with bound data using django

I have django form, but in my HTML i added one extra input field (directly added in html page) which i can access it using request.POST.get('extra_field_name') in my django views.
If form.is_valid() is false i can get the form as HTML with the data displayed in the HTML but with empty value for the extra added field( directly added in html page)
How can i get the bounded form data for this newly added extra html field after validation fials.
Please provide your suggestions?
View:
html_added_field = ''
error_added_field = None
if request.method == 'POST':
html_added_field = request.POST.get('extra_field_name')\
if form.is_valid():
pass
else:
error_added_field = _('Error')
context = {'html_added_field':html_added_field,'error_added_field':error_added_field}
HTML:
<input type="text" value="{{ html_added_field }}" />{% if error_added_field %}<div class="error">{{ error_added_field }}</div>{% endif %}
This article by Bennett may help you.
http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/
Briefly, you have to override the __init__ method of your form, adding there the new "extra_field_name". The fields are included in the self.fields list, so doing:
self.fields['extra_field_name'] = forms.CharField(put_here_definitions_for_your_field)
should do the trick.
Honestly the best way would be for your base django form to handle the extra field. Not using extra fields in the html. However if you can't/don't want, as xbello states, in http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/ you have various tricks for handling dynamic fields.
I found more robust to use the form factory method. A function that generates a dynamic form, prepared for more future changes. Still, you have to decide the best approach :-)

Categories

Resources