django - click the button and save create date in database - django

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>)

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.

How to save button value to databse in django?

I'm trying to create my first django app - sports predictions game.
I want user to select from three possible results using 3 buttons (images) which pass 3 different values to the db:
1 - home team wins
0 - draw
2 - away team wins
I am able to save data using forms when I type something into it, but how do I pass value of these buttons to my database?
code on my game.html:
{% csrf_token %}
{{ form }}
<input type="submit" value = 1>
<input type="submit" value = 0>
<input type="submit" value = 2> </form>
and my view:
def game(request, Game_id):
thisgame = get_object_or_404(Game, pk=Game_id)
nextgame = int(thisgame.id)+1
template = loader.get_template('polls/game.html')
form = NewBetForm(request.POST or None)
current_user = request.user
allgames = Game.objects.all()
betchoices = BetChoice.objects.all()
context = { 'thisgame': thisgame,
'nextgame': nextgame,
'form': form,
'current_user': current_user,
'betchoices': betchoices,}
if form.is_valid():
bet = form.save(commit=False)
bet.gameid = Game.objects.get(id=Game_id)
bet.userid_id = current_user.id
bet.save()
else:
print (form.errors)
and my form:
class NewBetForm(forms.ModelForm):
class Meta:
model = GameBet
fields = ['bet']
and the error I get is Bet - this field is required
Thank you for all ideas!
you can set name for it like :
<input type="submit" name="send1" value ="1">
Note : you should value part like value ="1"
and in views.py:
if request.method == 'POST':
if request.POST["send1"] == "1":
//do some thing
elif request.POST["send1"] == "2":
//do domthing
else://request.POST["send1"] == "3"
//do something
i hope it will help you :)
As with any other type of form field, a submit button needs a name attribute before it will send any data to the backend. From there, you can just pick up its value via request.POST['whatever_the_name_is'] and assign it to your newly created object - or, if you use the name that is already a field in the form, it will be assigned automatically.

Form fields missing in Django, just button visable

New to Django and having problem seeing form fields displayed. What I see is just the submit button. If pressed, the form is finally presented, but with the format for a form that had bad data (typical 'this field is required' error for each box, red box, etc).
The form works fine after entering data and again pressing submit (stores entries in my db). I have a number of forms on the same page that have the same behavior.
Example of one form:
#model
class dbPara(models.Model): #parameters
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
username = models.CharField(max_length=10)
turns = models.FloatField(default=27)
units = models.FloatField(default=5)
rise = models.FloatField(default=2.9)
rescutL = models.FloatField(default=0.0833333333)
rescutH = models.FloatField(default=0.333333333)
LorR = models.CharField(max_length=1, default='R')
def __str__(self):
return self.timestamp, self.username, self.turns, self.units, self.rise, self.rescutL, self.rescutH, self.LorR
#form
class ParaForm(ModelForm):
class Meta:
model = dbPara
widgets = {'username': forms.HiddenInput()}
fields =['username', 'turns', 'units', 'rise', 'rescutL', 'rescutH', 'LorR']
#view
def importParameters(request):
if request.method == 'GET':
form = ParaForm()
else:
form = ParaForm(request.POST)
if form.is_valid():
entry=dbPara(username = request.POST.get('username'),
turns = request.POST.get('turns'),
units = request.POST.get('units'),
rise = request.POST.get('rise'),
rescutL = request.POST.get('rescutL'),
rescutH = request.POST.get('rescutH'),
LorR = request.POST.get('LorR')
)
entry.save()
return render(request, 'main.html',
{'ParaHTML' : form })
#url
urlpatterns = patterns('Inputs.views',
url(r'^importParameters/$', 'importParameters', name='urlParameters'),
)
#main.html
<div class='col-lg-3'>
<h4>Set Rosetta Parameters</h4>
<action="{% url "urlParameters" %}" method="post">{% csrf_token %}
{{ ParaHTML|crispy }}
<input type="hidden" name = "username" value = "{{ user.get_username }}">
<input type="submit" class="btn btn-primary" value="Set">
</form>
</div>
Appreciate any advice (better simple than 'most correct but complicated')
Could it be due to using default in the model? Would that not 'fill in the form' and result in 'POST' at the initial visit to the page, resulting in just the button? Thoughts?
One Suggesestion here ....
if Using request.POST.get('anything') simply then it Will raise error if particular string not find as in example('anything') string...
Because request.POST.get('anything') will return None if 'anything' is not in request.POST.
Additionally, .get allows you to provide an additional parameter of a default value which is returned if the key is not in the dictionary.
e.g: Corrected will be request.POST.get('anything', 'mydefaultvalue')

SelectField option to dynamically populate default value in TextAreaField using WTForms

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.