SelectField option to dynamically populate default value in TextAreaField using WTForms - flask

I have a SelectField that is populated from a database table. I load the choices into the form as follows:
#statuses.route('/new', methods=['GET', 'POST'])
#login_required
def new_status():
form = StatusForm()
form.status_cd.choices = [(a.id, a.status_cd) for a in \
Status_Code.query.order_by('status_cd')]
if form.validate_on_submit():
status = Status(author=current_user)
form.to_model(status)
db.session.add(status)
db.session.commit()
flash('The status was added successfully.')
return redirect(url_for('.index'))
return render_template('statuses/new_status.html', form=form)
The model referenced in the query is as follows:
class Status_Code(db.Model):
__tablename__ = 'status_cd'
id = db.Column(db.Integer, primary_key=True)
status_cd = db.Column(db.String(16), nullable=False)
status_detail = db.Column(db.Text)
is_option_active = db.Boolean()
date_created = db.Column(db.DateTime, default=db.func.now())
And the form class is as follows:
class StatusForm(Form):
datetime = DateTimeField('Date / Time')
name = StringField('Name', validators=[Required()])
status_cd = SelectField('Status Code', coerce=int)
status_detail = TextAreaField('Status Detail', default="Default text",\
validators=[Required()])
submit = SubmitField('Submit')
The Question
Depending on the option selected in the SelectField, I want it to dynamically set the status_detail TextAreaField's default text. The value from the SelectField should query the database and return the status_detail, which should be the default text.
For example, if I have:
id status_cd status_detail
1 Apple The apples are red.
2 Banana The bananas are yellow.
If the user selects the "Apple" option, the default text should be "The apples are red."
Any assistance would be greatly appreciated! I am building my first Flask app so I'm new to this.

In my experience with flask, you can do this a couple of ways. There is no right way, and it is all up to you:
You can load the status_detail data, and place it in a data-detail tag in your select option value:
<select name='status_cd' onchange="get_status(this);">
{% for s in status %}
<option value='{{ s.id }}' data-detail='{{ s.status_detail }}'>{{ s.status_cd }} </option>
{% endfor %}
</select>
Then you can do an onchange with JavaScript, which can then get the data-detail value and update your text box (this is pseudo code, not meant for copy and paste):
<script>
function onchange(o){
var value = $(o).attr('data-detail');
//do something with the value
}
</script>
OR
You can do it where it pulls from the database dynamically if you don't wan to put the data-detail tag in your code, like this:
Same onchange with JavaScript, but can then do a call to an Ajax call to your routed method to return your value (this is pseudo code, not meant for copy and paste):
<script>
function onchange(o){
var value = $(o).value();
$.ajax({
url: '/my_rout',
data: value,
success : function(data){
//handle your result here
}
})
}
</script>
I hope this at least gets you in the right direction with some different options to choose from.

Related

Fields are not populated on update

I created a simple CRUD app using Flask and FlaskForm. I have a table where the last name, first name, birthdate, and sex are displayed coming from the database. Beside each name are links labeled as delete and update. When you click on update, you are routed to the update page with a form where the form fields corresponding to the last name, first name, birthdate, and sex should be populated. Sex is a select field with options Male and Female, how do I populate this based from the database? Using FlaskForm, I tried {{form.sex(value=user_to_update.sex)}} but it does not populate.
Here is my Update route:
#app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
form = Form()
user_to_update = TblPatient.query.get_or_404(id)
if request.method == 'POST':
user_to_update.lastname = form.lastname.data
user_to_update.firstname = form.firstname.data
user_to_update.birthdate = form.birthdate.data
user_to_update.sex = form.sex.data
db.session.commit()
return redirect(url_for('add_record'))
return render_template('update.html', form=form, user_to_update=user_to_update)
Here is the FlaskForm part:
class Form(FlaskForm):
lastname = StringField('Last Name', validators=[DataRequired()])
firstname = StringField('Firstname', validators=[DataRequired()])
birthdate = DateField('Date of Birth', format='%Y-%m-%d', validators=[DataRequired()])
sex = SelectField('Sex',
choices=['Select', 'Male', 'Female'],
default='Select',
validators=[DataRequired()])
submit = SubmitField('submit')
Here is my update.html where the form fields except for sex are populated:
<form action="{{request.path}}" method="post">
{{form.hidden_tag()}}
<fieldset>
<legend>Patient Info</legend>
<p>
{{form.lastname.label}} <br/>
{{form.lastname(value=user_to_update.lastname, size=30)}}
</p>
<p>
{{form.firstname.label}} <br/>
{{form.firstname(value=user_to_update.firstname, size=30)}}
</p>
<p>
{{form.birthdate.label}} <br/>
{{form.birthdate(value=user_to_update.birthdate)}}
</p>
<p>
{{form.sex.label}} <br/>
{{form.sex(value=user_to_update.sex)}}
</p>
</fieldset>
<br/>
{{form.submit}}
</form>
This is the home page:
When I click on update, it redirects me to the update page in question. How do I populate the sex field based on FlaskForm?
If the names of the database columns match those of the form's input fields, you can simply pass the database object to the form and the fields will be automatically populated. You do not need to pass the data to the input fields within the template.
patient = Patient.query.get_or_404(patient_id)
form = PatientForm(request.form, obj=patient)
An alternative to using the obj attribute is the assignment using the data attribute. See the documentation for the Form class.
In addition, you can then use the populate_obj function to transfer the form data to the database object.
form.populate_obj(patient)
The following example shows you how your endpoint should look like.
The patient is read from the database and assigned to the form. If the request is of type POST and the entries have been validated successfully, the patient data will be updated using the form.
#app.route('/update/<int:patient_id>', methods=['GET', 'POST'])
def update(patient_id):
patient = Patient.query.get_or_404(patient_id)
form = PatientForm(request.form, obj=patient)
if form.validate_on_submit():
form.populate_obj(patient)
db.session.commit()
return redirect(url_for('add_record'))
return render_template('update.html', **locals())

Django: how to increase object value

I'm trying to implement a simple 'like' button, however, the value of the object is not changing. I have only a week of experience with django, any help is appreciated!
model>
class Mainnews(models.Model):
author = models.ForeignKey(Author, on_delete=models.DO_NOTHING, default= True)
title = models.CharField(max_length=200)
description = models.TextField()
image = models.ImageField(upload_to = 'photos/%Y/%m/%d/')
is_published = models.BooleanField(default = True)
publish_date = models.DateTimeField(default = datetime.now, blank = True)
views_counter = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
def __str__(self):
return self.title
html>
<form action = "{% url 'like' %}" method = "POST">
{% csrf_token %}
<button type ='submit'>Like</button>
</form>
view>
def like(request):
if request.method == 'POST':
thelike = Mainnews.likes + 1
thelike.save()
url> on like redirect to homepage
path('news/', like, name = 'like'),
the ideal way to do it is using ajax ,so your page will not refresh every time you click the button,what missing in your question the condition of model which you want to increase ,in my code i set it news id you can change it ,check this :
<input id='news_id' name='news_id' >
<input type='button' onclick='Increase()' name='increase' >
<srcipt>
function Increase(){
var new_id= document.getElementById("news_id").value;
$.ajax({
type:"POST",
data:JSON.stringify({'data':new_id}),
success:function(responsedata){
// process on data
}
})
}
But if you want to use ajax you have to add a csrf_exempt decorator on your view
from django.views.decorators.csrf import csrf_exempt
#then write this before your view
#csrf_exempt
you can use F() object to generate a SQL expression that describes the required operation without actually having to pull them out of the database into Python memory check here you can use this :
if request.is_ajax():
new_id = json.loads(request.body.decode('utf-8'))["data"]
_reponse = Mainnews.objects.filter(id=new_id).update(likes=F('likes') + 1)
return JsonResponse({'data_to_return':'data'})
As stated in the comments by both Mahdi and Abdul, you shouldn't need a form to increase the value of Likes for a particular Mainnews instance. This can be done just by creating a URL and view specific to this purpose.
First, you will need to create a view specifically for increasing likes against a Mainnews instance. That view should look something like this:
def add_likes(request, news_id):
news_instance = Mainnews.objects.get(id=news_id)
news_instance.likes = news_instance.likes += 1
news_instance.save()
# Assuming that you want to display the same news instance again, you would need to send back the same instance to the news instance view
context = {
'news_instance': news_instance,
}
return render(request, 'your_template_here', context=context)
You will also need to create a URL path for updating likes. That should look something like this:
path('/news_item/add_like/<int:news_id>', add_likes, name='your-url-name'),
Then finally you would need to update your news template something like this (assuming you are using CSS to drive your front end):
Add Like
This will result in the page being refreshed by the user when they click on the "Like" button. If that is not the behavior you want, the answer submitted by Belhadjer would probably help prevent the refresh.

django - click the button and save create date in database

Database:
database
Model :
class Donor(models.Model):
firstName = models.CharField(max_length=50)
lastName = models.CharField(max_length=50)
bloodType = models.CharField(max_length=10)
createdDate = models.DateTimeField(auto_now_add=True)
lastAttendance = models.DateTimeField(auto_now_add=True)
View:
donor_id = None
if request.method == "GET":
donor_id = request.GET['id']
if donor_id:
donor = Donor.objects.get(id=int(donor_id))
if donor:
donor.createdDate = True
donor.save()
Error message: MultiValueDictKeyError at /donors/
"'id'"
Problem:
approach
Click the attentd button, take user's id and save in the database current date.
Any solutions appreciated!!
You need to add value in button so you can get value as GET parameter.
<form action="get">
<button
type="submit"
class="btn attendBtn"
value="{{ item.id }}"
name="attend">attend
</button>
</form>
Normally in input buttons we don't specify value attribute, It's because user entered value and submit the button for processing. But in your case we need to declare explicitly value.
Try
if request.method == "GET":
donor_id = request.GET.get('id')
request.GET['key'] would raise a KeyError if the key doesn't exist.
request.GET.get('key', '') allows us to specify a default value, if the key is not available. If omitted, the default value is ''. So, it won't raise error, if there is no id in the request.GET
Use the MultiValueDict's get method. This is also present on standard dicts and is a way to fetch a value while providing a default if it does not exist.
donor_id = request.GET.get('id', False)
Generally,
my_var = dict.get(<key>, <default>)

In django admin, is it possible to dynamically filter available choices based on on previous field selection [duplicate]

I've been scanning through Django documentation, and Google search results, all afternoon and I'm still somewhat stuck in my attempt to create a dynamic form. I'm hoping I just need someone to nudge me in the right direction :-) I'm just starting to learn Django, so I'm still very much a beginner; however, I'm already an intermediate python user.
What I'm trying to do is create a dynamic form, where the user makes a selection from a drop-down menu, and based on that selection another part of the form will automatically update to display results relevant to the currently selected item, but from another database table.
I'll try and use a simplified version of the models from the Django tutorial to better illustrate what I'm trying to do:
# models.py
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
So lets say I want to have something like a drop-down selection field, populated with the question from each Poll in the database. I also want to have a text-field, which displays the corresponding choices for the currently selected Poll, which will update on-the-fly whenever the user selects a different Pool. I've been able to figure this out by placing a button, and posting information back to the form; However, I'm trying to do this automatically as the user makes a selection. My view sort of looks something like this at the moment:
#view.py
from django import forms
from django.shortcuts import render_to_response
from myapp.models import Poll,Choice
class MyModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s" % obj.question
class PollSelectionForm(forms.Form):
polls = MyModelChoiceField( queryset=Poll.objects.all() )
class ChoiceResults(forms.Form):
def __init__(self, newid, *args, **kwargs):
super(ChoiceResults, self).__init__(*args, **kwargs)
self.fields['choice'] = forms.TextField( initial="" )
def main(request):
return render_to_response("myapp/index.html", {
"object": PollSelectionForm(),
"object2": ChoiceResults(),
})
My template is very simple, just something like
{{ object }}
{{ object2 }}
I'm sure the way I'm going about creating the forms is probably not the best either, so feel free to criticize that as well :-) As I mentioned, I've read solutions involving reposting the form, but I want this to happen on-the-fly... if I can repost transparently then that would be fine I guess. I've also seen libraries that will let you dynamically create forms, but that just seems like overkill.
Here is one approach - Django/jQuery Cascading Select Boxes?
You can create a new view that just renders json to a string,
and then trigger an event when you're done selecting from the first list which loads the data dynamically from that json.
I do a similar thing here, populating a form based on a selection in a drop down. Maybe this helps you.
Here is the model of the values used to pre-populate the form:
class OpmerkingenGebrek(models.Model):
opmerking = models.CharField(max_length=255)
advies = models.CharField(max_length=255)
urgentiecodering = models.CharField(max_length=2, choices=URGENTIE_CHOICES_2011)
bepaling = models.CharField(max_length=155,blank=True,null=True)
aard = models.CharField(max_length=3, choices=AARD_CHOICES)
The view that manages the form:
def manage_component(request,project_id,.....):
# get values for pre-populate
og = OpmerkingenGebrek.objects.all()
.........
formset = ComponentForm(request.POST,request.FILES)
.........
)))
return render_to_response(template, {
'formset':formset,
........
'og':og,
},context_instance=RequestContext(request))
The html the renders the form
{% extends "base.html" %}
{% block extra_js %}
<script type="text/javascript" src="/media/js/limitText.js"></script>
<script type="text/javascript" src="/media/js/getValueOpmerking.js"></script>
{% endblock %}
<form enctype="multipart/form-data" method="post" action="">
{{ formset.as_table }}
</form>
<p>Choose default values:</p>
<select id="default" onChange="getValue(this)">
{% for i in og %}
<option value="{{ i.opmerking }} | {{ i.advies }} | {{ i.urgentiecodering }} |
{{ i.aard }} | {{ i.bepaling }}">{{ i.opmerking }}</option>
{% endfor %}
</select>
The javascript that pre-populates the form:
function getValue(sel)
{
//get values
var opm = sel.options[sel.selectedIndex].value;
//split string to parts
var parts = opm.split("|");
// autofill form
var opmerking = document.getElementById("id_opmerking");
opmerking.value = parts[0];
var aanbeveling = document.getElementById("id_aanbeveling");
aanbeveling.value = parts[1];
var opt = document.getElementById("id_urgentie");
var urgentie = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[2].split(' ').join('')){
opt.selectedIndex = i;
}};
var opt = document.getElementById("id_aard");
var aard = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[3].split(' ').join('')){
opt.selectedIndex = i;
}};
var bepaling = document.getElementById("id_bepaling");
bepaling.value = parts[4];
};

Django dynamic forms - on-the-fly field population?

I've been scanning through Django documentation, and Google search results, all afternoon and I'm still somewhat stuck in my attempt to create a dynamic form. I'm hoping I just need someone to nudge me in the right direction :-) I'm just starting to learn Django, so I'm still very much a beginner; however, I'm already an intermediate python user.
What I'm trying to do is create a dynamic form, where the user makes a selection from a drop-down menu, and based on that selection another part of the form will automatically update to display results relevant to the currently selected item, but from another database table.
I'll try and use a simplified version of the models from the Django tutorial to better illustrate what I'm trying to do:
# models.py
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
So lets say I want to have something like a drop-down selection field, populated with the question from each Poll in the database. I also want to have a text-field, which displays the corresponding choices for the currently selected Poll, which will update on-the-fly whenever the user selects a different Pool. I've been able to figure this out by placing a button, and posting information back to the form; However, I'm trying to do this automatically as the user makes a selection. My view sort of looks something like this at the moment:
#view.py
from django import forms
from django.shortcuts import render_to_response
from myapp.models import Poll,Choice
class MyModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s" % obj.question
class PollSelectionForm(forms.Form):
polls = MyModelChoiceField( queryset=Poll.objects.all() )
class ChoiceResults(forms.Form):
def __init__(self, newid, *args, **kwargs):
super(ChoiceResults, self).__init__(*args, **kwargs)
self.fields['choice'] = forms.TextField( initial="" )
def main(request):
return render_to_response("myapp/index.html", {
"object": PollSelectionForm(),
"object2": ChoiceResults(),
})
My template is very simple, just something like
{{ object }}
{{ object2 }}
I'm sure the way I'm going about creating the forms is probably not the best either, so feel free to criticize that as well :-) As I mentioned, I've read solutions involving reposting the form, but I want this to happen on-the-fly... if I can repost transparently then that would be fine I guess. I've also seen libraries that will let you dynamically create forms, but that just seems like overkill.
Here is one approach - Django/jQuery Cascading Select Boxes?
You can create a new view that just renders json to a string,
and then trigger an event when you're done selecting from the first list which loads the data dynamically from that json.
I do a similar thing here, populating a form based on a selection in a drop down. Maybe this helps you.
Here is the model of the values used to pre-populate the form:
class OpmerkingenGebrek(models.Model):
opmerking = models.CharField(max_length=255)
advies = models.CharField(max_length=255)
urgentiecodering = models.CharField(max_length=2, choices=URGENTIE_CHOICES_2011)
bepaling = models.CharField(max_length=155,blank=True,null=True)
aard = models.CharField(max_length=3, choices=AARD_CHOICES)
The view that manages the form:
def manage_component(request,project_id,.....):
# get values for pre-populate
og = OpmerkingenGebrek.objects.all()
.........
formset = ComponentForm(request.POST,request.FILES)
.........
)))
return render_to_response(template, {
'formset':formset,
........
'og':og,
},context_instance=RequestContext(request))
The html the renders the form
{% extends "base.html" %}
{% block extra_js %}
<script type="text/javascript" src="/media/js/limitText.js"></script>
<script type="text/javascript" src="/media/js/getValueOpmerking.js"></script>
{% endblock %}
<form enctype="multipart/form-data" method="post" action="">
{{ formset.as_table }}
</form>
<p>Choose default values:</p>
<select id="default" onChange="getValue(this)">
{% for i in og %}
<option value="{{ i.opmerking }} | {{ i.advies }} | {{ i.urgentiecodering }} |
{{ i.aard }} | {{ i.bepaling }}">{{ i.opmerking }}</option>
{% endfor %}
</select>
The javascript that pre-populates the form:
function getValue(sel)
{
//get values
var opm = sel.options[sel.selectedIndex].value;
//split string to parts
var parts = opm.split("|");
// autofill form
var opmerking = document.getElementById("id_opmerking");
opmerking.value = parts[0];
var aanbeveling = document.getElementById("id_aanbeveling");
aanbeveling.value = parts[1];
var opt = document.getElementById("id_urgentie");
var urgentie = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[2].split(' ').join('')){
opt.selectedIndex = i;
}};
var opt = document.getElementById("id_aard");
var aard = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[3].split(' ').join('')){
opt.selectedIndex = i;
}};
var bepaling = document.getElementById("id_bepaling");
bepaling.value = parts[4];
};