Flask-wtf SelectMultipleField: how to configure default choices - flask

In my app I use a among others a SelectMultipleField ("stektypes") for creating “stekken”, using the following form:
class createStekForm(FlaskForm):
name = StringField("Naam van de stek", validators=[DataRequired()])
water = StringField("Naam van het water", validators=[DataRequired()])
description = TextAreaField("Beschrijving van het water")
stektypes = SelectMultipleField(u'Stektypes', coerce=int)
street = StringField("Straat", validators=[DataRequired()])
number = StringField("Nummer", validators=[DataRequired()])
postalcode = StringField("Postcode", validators=[DataRequired()])
place = StringField("Plaats", validators=[DataRequired()])
country = StringField("Land", validators=[DataRequired()])
latitude = DecimalField("Latitude", validators=[DataRequired()])
longitude = DecimalField("Longitude", validators=[DataRequired()])
saveStek = SubmitField("Bewaar stek")
navigateTo = SubmitField("Navigeer naar stek")
addToSession = SubmitField("Voeg stek toe aan sessie")
So far so good.
Somewhere else in the app I want to modify an individual “stek”, using a similar SelectMultipleField, but then initialized with the earlier defined values.
From the documentation [https://wtforms.readthedocs.io/en/2.3.x/fields/][1] I learned that that is possible as follows…
class wtforms.fields.SelectMultipleField(default field arguments,
choices=[], coerce=unicode, option_widget=None)
In my case it does not work.
The view from which I am calling the form is as follows.
#stekken.route('/stek_modify<stekId>', methods=['GET', 'POST'])
#login_required
def stek_modify(stekId):
form = createStekForm() # coerce needs to be set in form definition!!!
form.stektypes.choices = [(1, "aa"), (2, "bb"), (3, "cc"), (4, "dd")]
#form.stektypes.default = (2, 'bb')
#form.stektypes.default = 2
form.stektypes.default = 'bb'
if form.validate_on_submit():
......
......
return render_template('stek_modify.html', form=form, user=current_user, stek=selectedStek, key=current_app.config["GOOGLEMAPS_KEY"])
Any hints / tips would be appreciated.

Related

Django: how to modify form field order of bound form with one unbound field?

I have an update form with 4 fields to display
3 of them are related to a class to which the form is bound
the last field (country) is only for information and I would like that field to be display in first position
currently, it is displayed at the end of my form...
I tryed to use field_order but country field is ignored...
form.py
class ParametrageForm(forms.ModelForm):
def __init__(self, request, *args, **kwargs):
super(ParametrageForm, self).__init__(*args, **kwargs)
self.request = request
self.language = request.session.get('language')
self.user = request.user.id # id de l'utilisateur
self.user_pays = request.session.get('user_pays') # pays de l'utilisateur
self.user_site_type = request.session.get('user_site_type')
self.user_site = request.session.get('user_site')
instance = Parametrage.objects.get(asp_par_cle = kwargs['instance'].asp_par_cle)
SITE_CONCERNE = Site.option_list_sites(self.language)
if self.language == 'en':
country= Site.objects.get(sit_abr = instance.asp_par_loc).reg.pay.pay_nom_eng
elif self.language == 'fr':
country= Site.objects.get(sit_abr = instance.asp_par_loc).reg.pay.pay_nom_fra
else:
country= Site.objects.get(sit_abr = instance.asp_par_loc).reg.pay.pay_nom_eng
self.fields["country"] = forms.CharField(label = _("Country"),widget=forms.TextInput,initial=country, disabled=True)
self.fields["asp_par_loc"] = forms.ChoiceField(label = _("Site concerned by settings"), widget=forms.Select, choices=SITE_CONCERNE,)
self.fields["asp_par_ale"] = forms.IntegerField(label = _("Stock alert value for this site"), widget=forms.TextInput,)
self.fields["asp_par_con"] = forms.IntegerField(label = _("Stock confort value for this site"), widget=forms.TextInput,)
class Meta:
model = Parametrage
fields = ('asp_par_loc','asp_par_ale','asp_par_con',)
field_order = ['country','asp_par_loc','asp_par_ale','asp_par_con',]
Replace
self.fields["country"] = forms.CharField(label = _("Country"),widget=forms.TextInput,initial=country, disabled=True)
with
country = forms.CharField(label = _("Country"),widget=forms.TextInput,initial=country, disabled=True)
I found how to solve my issue:
I defined 'country' field outside of the init
and then filed_order works
but doing that, I do not have access to my initial country value, set in init (country= Site.objects.get(sit_abr = instance.asp_par_loc).reg.pay.pay_nom_eng)
I must improve my Python understanding...

How can I calculate avg of data from django form and store in variable for later use?

In the readerpage function, in my views.py, I am trying to calculate the avg of the two variables: readability_rating and actionability_rating, and store the result in avg_rating
def readerpage(request, content_id):
content = get_object_or_404(Content, pk=content_id)
form = ReviewForm(request.POST)
if form.is_valid():
review = form.save(commit=False)
review.content = content
readability_rating = form.cleaned_data['readability_rating']
readability = form.cleaned_data['readability']
actionability_rating = form.cleaned_data['actionability_rating']
actionability = form.cleaned_data['actionability']
general_comments = form.cleaned_data['general_comments']
review.avg_rating = (float(readability_rating) +
float(actionability_rating)) / 2
review.save()
return redirect('home')
args = {'content': content, 'form': form}
return render(request, 'content/readerpage.html', args)
The problem is that with this setup the two variables are still ChoiceFields - as such the above setup gives me the error:
float() argument must be a string or a number, not 'ChoiceField'
I’ve tried converting them to floats without any luck.
I also attempted using the TypedChoiceField with coerce=float, still with no luck
I’m not sure whether the best place to calculate this is in my function, my form, or my model?
models.py:
class Review(models.Model):
content = models.ForeignKey(Content, null=True, on_delete=models.CASCADE)
readability = models.CharField(null=True, max_length=500)
readability_rating = models.IntegerField(null=True)
actionability = models.CharField(null=True, max_length=500)
actionability_rating = models.IntegerField(null=True)
general_comments = models.CharField(null=True, max_length=500)
avg_rating = models.FloatField(null=True)
def _str_(self):
return self.title
forms.py:
class ReviewForm(forms.ModelForm):
readability = forms.CharField(widget=forms.Textarea)
readability_rating = forms.ChoiceField(
choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)])
actionability = forms.CharField(widget=forms.Textarea)
actionability_rating = forms.ChoiceField(
choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)])
general_comments = forms.CharField(widget=forms.Textarea)
class Meta:
model = Review
fields = ['readability', 'readability_rating',
'actionability', 'actionability_rating', 'general_comments']
Thanks for reading this.
The variables are ChoiceFields because you are declaring them as ChoiceFields in view function. Shouldn't you just fetch the values from your cleaned_data?
readability_rating = form.cleaned_data['readability_rating']
And to the second part of your question: Why not add it as a #property to your model?

If Else in Djnago Views

I'm making a LMS.
Where a User applies for a leave and the admin accepts or rejects it.
Right now I am stuck in a problem where I want the user to apply for a leave through the Django form by selecting a leave type (casual, sick, half pay etc), if the admin accepts it then the default values in the database changes or gets deducted from the Employee model and when the counter reaches 0 an error is generated that you don't have any leaves,contact the admin.
I'm unable to understand how to make the logic for it.
I tried Applying if else statement in the views and even in the models.
views.py
The function name is "Reject" as I am trying to make changes to the accept function.
def reject_leave(request, id):
# employee_item = Employee.objects.get(id=id)
all_item = Leave.objects.get(id=id)
all = Employee.objects.get(id=id)
context = {'all': all,'all_item': all_item}
'''
if the leave_type (choice field of the leaves from the django form) equals to a leave type like Annual leave
The the program deducts 1 or the amount entered from the total value of Annual leave from the Model Employee
'''
*Sorry for the poor writing I'm not experienced in Django*
***This code is saying that in an illogical way.***
if leave_type.id is "Annual_leave":
Annual_leave - 1
else:
subject = "Leave Rejected" # email subject
email_from = "settings.EMAIL_HOST_USER" # email from
to_email = ['someemail#something.com'] # email to
with open(...) as f:
msgbody = f.read()
msg = EmailMultiAlternatives(
subject=subject, body=msgbody, from_email=email_from, to=to_email)
html_template = get_template(...).render()
msg.attach_alternative(html_template, "text/html")
msg.send()
return render(request, 'projectfiles/rejectemail.html',context)
forms.py
class Leave_Form(forms.ModelForm):
to_date = forms.DateField(
widget=forms.DateInput(format=('%m/%d/%y'),
attrs={'class': 'form-control',
'placeholder': ' Month/Date/Year'}))
from_date = forms.DateField(
widget=forms.DateInput(format=('%m/%d/%y'),
attrs={'class': 'form-control',
'placeholder':' Month/Date/Year'}))
class Meta:
model = Leave
fields = ['leave_Type', 'description',
'from_date', 'to_date', 'leave_qty']
exclude = ['employee_leaves', 'submit_date']
leave_type_choice = (
("Annual_leave", "Annual leave"),
("Sick_leave", "Sick leave"),
("Casual_leave", "Casual leave"),
("Emergency_leave", "Emergency leave"),
("Half_pay","Half Pay")
)
widgets = {
'leave_Type': forms.Select(choices = leave_type_choice, attrs={'class': 'form-control'}),
'description': forms.Textarea(
attrs={'class': 'form-control','placeholder': 'Enter description here', 'rows': 3, 'cols': 21})}
models.py
class Employee(models.Model):
employee_name = models.OneToOneField(User, on_delete = models.CASCADE)
employee_designation = models.CharField(max_length = 20)
employee_department = models.CharField(max_length = 35)
Annual_leave = models.PositiveSmallIntegerField(default=10)
Sick_leave = models.PositiveSmallIntegerField(default=3)
Casual_leave = models.PositiveSmallIntegerField(default=3)
Half_pay = models.PositiveSmallIntegerField(default=4)
Emergency_leave = models.PositiveSmallIntegerField(default=3)
allowed = models.BooleanField(default=False)
def __str__(self):
return self.employee_name.username
class Meta:
verbose_name_plural = "Employee"
class Leave(models.Model):
employee_leaves = models.ForeignKey(Employee, on_delete=models.CASCADE)
leave_Type = models.CharField(max_length=25)
leave_qty = models.PositiveSmallIntegerField(default=0)
description = models.CharField(max_length=75, blank=True, null=True)
submit_date = models.DateTimeField(auto_now_add=True)
from_date = models.DateField(auto_now=False, auto_now_add=False)
to_date = models.DateField(auto_now=False, auto_now_add=False)
class Meta:
verbose_name_plural = "Leave"
def __str__(self):
return self.leave_Type + " by " + str(self.employee_leaves)
When the Admin accepts (or in this case rejects) a leave.
e.g.
Sick leave I want 1 or entered amount of leaves to be deducted from the total of the allocated sick leaves.
def reject_leave(request, id): # overwriting built-in id is not a good idea
all_item = Leave.objects.get(id=id) # This is a single item, not all items
all = Employee.objects.get(id=id) # this again is a single item, not all items
context = {'all': all, 'all_item': all_item}
if leave_type.id is "Annual_leave":
# What is leave_type?
Annual_leave - 1
# What is Annual_leave? What does -1 supposed to do?
# Maybe you meant
# employee = Employee.objects.get(id=id)
# leave = employee.employee_leaves_set.last()
# if leave.leave_Type == 'Annual_leave':
# employee.Annual_leave -= 1
# employee.save()
else:
subject = "Leave Rejected"
email_from = "settings.EMAIL_HOST_USER"
to_email = ['talhamurtaza#clickmail.info']
with open('...') as f:
msgbody = f.read()
msg = EmailMultiAlternatives(
subject=subject, body=msgbody, from_email=email_from, to=to_email)
html_template = get_template(
"...").render()
msg.attach_alternative(html_template, "text/html")
msg.send()
return render(request, 'projectfiles/rejectemail.html', context)
There is so many things wrong with this that I can confidently say you haven't taken a python tutorial, read pep-8 nor taken a django tutorial. So please start from the first one and work your way up.

Unable to save checkbox data

i am really exhausted i didn't find any solution for this till now. I was trying to create a table to view all the data save by the user. The problem is that all the inputs in the models.py are saved excluding the parameters with checkbox. I don't know what is the problem. All these parameters in models.py are saved in the database.
This is my Models.py :
class Parameters(models.Model):
user = models.ForeignKey(User)
title = models.CharField('title', max_length=100, default='', blank=True, help_text='Use an indicative name, related to the chosen parameters')
type = models.CharField('forecast type', choices=FORECAST_TYPES, max_length=20, default="backtest")
#input characteristics
price_1_min = models.FloatField('1. Price, min', default=0.1, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
price_1_max = models.FloatField('1. Price, max', default=20000, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
stocks_num_2_min = models.IntegerField('2. Number of selected stock, min', default=3, validators=[MinValueValidator(0), MaxValueValidator(100)])
stocks_num_2_max = models.IntegerField('2. Number of selected stock, max', default=7, validators=[MinValueValidator(1),])
limit_3 = models.FloatField('3. Last price to upper straight, %', default=20, validators=[MinValueValidator(-200),])
learning_days_4_min = models.IntegerField('4. Number of Learning days, min', default=1, validators=[MinValueValidator(1),MaxValueValidator(30)])
learning_days_4_max = models.IntegerField('4. Number of Learning days, max', default=10, validators=[MinValueValidator(1),MaxValueValidator(30)])
evaluation_days_5 = models.IntegerField('5. Number of Evaluation days', default=10, validators=[MinValueValidator(1),MaxValueValidator(10)])
delay_days_6 = models.IntegerField('6. Number of “no quarterly reports” days (N)', default=10, validators=[MinValueValidator(0),MaxValueValidator(20)])
minimum_gain_7 = models.FloatField('7. Minimum gains for winners', default=0, validators=[MinValueValidator(0),MaxValueValidator(100)])
minimum_loss_8 = models.FloatField('8. Minimum losses for losers', default=0, validators=[MinValueValidator(-100),MaxValueValidator(0)])
total_gain_min_9 = models.FloatField('9. Minimum total gain', default=0, validators=[MinValueValidator(0),MaxValueValidator(100)])
winning_stock_percentage_min_10 = models.FloatField('10. Minimum percentage of winning stocks', default=60, validators=[MinValueValidator(0),MaxValueValidator(100)])
#input characteristics
period_start = models.DateField('period, start', default=datetime.date(2013, 9, 25))
period_end = models.DateField('end', default=datetime.datetime.today().date() - datetime.timedelta(days=16))
inital_capital = models.IntegerField('Total initial capital, USD', default=100000, validators=[MinValueValidator(10000),])
fraction_to_invest = models.FloatField('Percentage of the available capital to (re)invest', default=50, validators=[MinValueValidator(10), MaxValueValidator(90)])
minimum_cash = models.IntegerField('Minimum cash to invest, %', default=5, validators=[MinValueValidator(1), MaxValueValidator(50)])
trades_fees = models.FloatField('Trade fees, USD', default=8, validators=[MinValueValidator(0),])
stop_loss = models.FloatField('Stop-Loss, %', default=-2, validators=[MinValueValidator(-50), MaxValueValidator(-1)])
target_gain = models.FloatField('Target gain, %', default=5, validators=[MinValueValidator(1),])
created_at = models.DateTimeField(u'created', auto_now_add=True)
updated_at = models.DateTimeField(u'updated', auto_now=True)
This is the forms.py: All the inputs with multiplechoice field are empty after save
class BacktestForm(forms.ModelForm):
period_start = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=365+16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])
period_end = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])
market = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices=MARKET_CHOICES)
sector = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices= MEDIA_CHOICES)
class Meta:
model = Parameters
exclude = [
'user',
'type',
'created_at',
'updated_at',
]
widgets={
'title': forms.TextInput(attrs={'placeholder':'for ex. highLimitLowPrice'}),
}
The function of save in view.py:
def backtest(request, pk=None):
if pk is not None:
param = get_object_or_404(Parameters, pk=pk, user=request.user)
form = BacktestForm(request.POST or None, instance=param)
else:
form = BacktestForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
if 'save' in request.POST:
obj = form.save(commit= False)
obj.user = request.user
obj.type = "backtest"
obj.save()
messages.info(request, 'Saved!')
return redirect(obj.get_backtest_url())
else:
messages.info(request, 'Please check entered data')
data = {
'active_page': 'backtest',
'form': form,}
In models.py
class Parameters(models.Model):
...
MARKET = (
(1,'First'),
(2,'Second')
)
SECTOR= (
(1,'First'),
(2,'Second')
)
market = models.CharField('Market', max_length=30, null=True)
sector= models.CharField('Sector', max_length=30, null=True)
def display_sector_label(self)
sectors= [(str(dict(self.SECTOR)[value])) for value in self.sector]
return ", ".join(sectors)
def display_market_label(self)
markets = [(str(dict(self.MARKET)[value])) for value in self.market]
return ", ".join(markets)
In forms.py
class BacktestForm(forms.ModelForm):
market = forms.MultipleChoiceField(
label='Market',
choices=Parameters.MARKET,
widget=forms.CheckboxSelectMultiple
)
sector = forms.MultipleChoiceField(
label='Sector',
choices=Parameters.SECTOR,
widget=forms.CheckboxSelectMultiple
)

ORM filter has no results

I have a view:
def PeopleView(request):
...
parameters = copy.deepcopy(request.GET)
for parameter in request.GET:
if not request.GET.get(parameter):
del parameters[parameter]
people = Person.objects.filter(**parameters)
search_form = PersonSearchForm()
return render(request, 'persons/people.html', {
'people': people,
'search_form': search_form,
...
})
PersonSearchForm:
class PersonSearchForm(forms.Form):
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
second_name = forms.CharField(required=False)
country = forms.CharField(required=False)
city = forms.CharField(required=False)
gender = forms.CharField(widget=forms.Select, required=False)
birthday = forms.DateField(required=False)
school = forms.CharField(required=False)
university = forms.CharField(required=False)
profession = forms.CharField(required=False)
Person model has fields from PersonSearchForm with the same name. And this form is sent by user as GET request.
GET request and print of parameters variable:
However filter always has no results. What's wrong?
SOLUTION
I solved the problem. The solution is a transformation of querydict parameters to dict object. It looks like:
...
filter_parameters = {}
for parameter in parameters:
filter_parameters[parameter] = parameters[parameter]
people = Person.objects.filter(**filter_parameters)
...
And it works.