Edit form creates new data instead - python

I defined a route and template to edit data. Instead, it creates new data. How do I fix this?
#home_blueprint.route('/table/<int:data_id>/edit', methods=['GET', 'POST'])
def edit(data_id):
ed_form = EditTableForm(request.form)
data_to_edit = db.session.query(Diary).filter_by(id=data_id)
if ed_form.validate_on_submit():
if ed_form.title.data:
data_to_edit.title = ed_form.title.data
if ed_form.weight.data:
data_to_edit.weight = ed_form.weight.data
if ed_form.kkal.data:
data_to_edit.kkal = ed_form.kkal.data
if ed_form.carbs.data:
data_to_edit.carbs = ed_form.carbs.data
if ed_form.proteins.data:
data_to_edit.proteins = ed_form.proteins.data
if ed_form.fats.data:
data_to_edit.fats = ed_form.fats.data
db.session.add(data_to_edit)
db.session.commit()
flash('New data was successfully posted. Thanks.')
return redirect(url_for('home.table'))
else:
return render_template('edit.html', data_to_edit=data_to_edit, ed_form=ed_form, data_id=data_id)
return render_template("edit.html", diary=diary)
<table class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th>Weith</th>
<th>Kkal</th>
<th>Protein</th>
<th>Fat</th>
<th>Carbs</th>
</tr>
</thead>
<tbody>
{% for data in data_to_edit %}
<tr>
<form class="form-message" role="form" method="post" action="/table">
{{ ed_form.csrf_token }}
<td>{{ed_form.title(placeholder=data.title)}}</td>
<td>{{ed_form.weight(placeholder=data.weight)}}</td>
<td>{{ed_form.kkal(placeholder=data.kkal)}}</td>
<td>{{ed_form.carbs(placeholder=data.carbs)}}</td>
<td>{{ed_form.proteins(placeholder=data.proteins)}}</td>
<td>{{ed_form.fats(placeholder=data.fats)}}</td>
<td><button class="btn btn-sm btn-success" type="submit">Post</button></td>
</form>
</tr>
{% endfor %}
</tbody>
</table>
Link to projects Git repository. Each users input into table has own id, I query data by id and then trying to Edit data there with no luck so far :)
UPDATE
I have changed code to:
data_to_edit = db.session.query(Diary).filter_by(id=data_id).first()
if ed_form.validate_on_submit():
if not data_to_edit:
data_to_edit = Diary(
ed_form.title.data,
ed_form.weight.data,
ed_form.kkal.data,
ed_form.carbs.data,
ed_form.proteins.data,
ed_form.fats.data,
current_user.id
)
db.session.add(data_to_edit)
db.session.commit()
But yet no luck, it doesn't change old data but ads new.

The issue is that you are adding the object again in session, thus inserting it into the database.
Sample code
data_to_edit = db.session.query(Diary).filter_by(Diary.id=data_id).first()
if not data_to_edit:
data_to_edit = Diary()
db.session.add(data_to_edit)
...
# edit properties
...
db.session.commit()
The idea is to add the new object only when it's actually new.

Related

How can I add a column to a table using jinja

First of all let me tell you that I'm a beginner at this, I'm on the final project of CS50x. My project consists in a webpage that lets you add some weights into a db table, and then it displays those weights and shows you the weight gain/loss. I'm trying to show the results of a query in a table rendered in html using jinja (and python). RP is the identifier(you search for the rp). The desired output is something like this:
[Desired output]
My python code is the following:
#app.route("/weightquery", methods=["GET", "POST"])
#login_required
def weightquery():
if request.method == "POST":
weights = db.execute("SELECT rp, weight, date FROM weights WHERE rp=:rp AND sex=:sex AND user_id=:user_id ORDER BY date DESC",
rp=request.form.get("rp"), sex=request.form.get("sex"), user_id=session["user_id"])
gains = db.execute("SELECT weight FROM weights WHERE rp=:rp AND sex=:sex AND user_id=:user_id ORDER BY date DESC",
rp=request.form.get("rp"), sex=request.form.get("sex"), user_id=session["user_id"])
animal = request.form.get("rp")
for i in range(len(gains)):
for weight in gains[i]:
if i >= 0 and i < (len(gains)-1):
dif= gains[i][weight] - gains[i + 1][weight]
# Store the dif somewhere I can access.
gains[i].update({'weight': dif})
# Since the dif will always have one item less, I make sure to delete the last item.
gains[i].popitem()
return render_template("weightqueried.html", weights=weights, gains=gains, animal=animal, dif=dif)
else:
return render_template("weightquery.html")
My Html template for weightqueried.html is:
{% block main %}
<div class="container">
<h3>{{ animal }}'s information</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Weight(kg)</th>
<th>Weight dif(kg)</th>
</tr>
</thead>
<tbody>
{% for rp in weights %}
<tr>
<td>{{ rp['date'] }}</td>
<td>{{ rp['weight'] }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
</tfoot>
</div>
{% endblock %}
Any tips and pointers are greatly appreciated since I'm trying to learn and right now my brain is fried!
Maybe it can be simplified if gains was removed entirely. Iterate over weights, do the dif calculation, and add the result to each dictionary. Then in the template, add a <td> element for rp['dif']. If I understand the problem correctly.....

How to properly call to my “delete” endpoint with id and delete the row from SQL on user click?

This is the Python code I have written to display the table and to delete the row from the table. The display table is working fine. But, I am not able to delete the row from the table.
How do I send the ID properly to my endpoint?
#app.route('/showTable')
def showTable():
cursor2.execute("select * from web2")
data = cursor2.fetchall()
#data.set_index(['id'], inplace=True)
#data.index.name = None
return render_template('showTable.html',data=data)
#app.route('/showTable/<id>', methods=['GET','POST'])
def delete_row():
if request.method=="POST":
id=request.form.get("id")
#cursor3.execute('delete from web2 where id = ?', [request.form['row_to_delete']])
cursor3.execute('delete from web2 where id= ?', [id])
conn.commit()
#data = cursor3.fetchall()
#return '<h1>New record has been deleted!</h1>'
flash('Record Deleted', 'success')
#return redirect(url_for('showTable'))
return render_template('showTable.html',id=id)
if __name__ == "__main__":
#app.debug = True
app.run(debug=True,port=8080)
#HTML code for the same:-
<link rel="stylesheet" href="{{url_for('.static', filename='signin.css')}}">
New Duplicate Account
<table border="1" cellpadding="2" cellspacing="0">
{% for row in data %}
<tr>
{% for d in row %}
<td>{{ d }}</td>
{% endfor %}
<form action="{{ url_for('delete_row') }}" method="post" action="/showTable">
<input type=hidden value="{{ id }}" name="row_to_delete"></input>
<td><button class="btn btn-lg btn-primary btn-block" type="submit">Delete</button></td>
</form>
</tr>
{% endfor %}
</table>
<p></p>
werkzeug.routing.BuildError: Could not build url for endpoint 'delete_row'. Did you forget to specify values ['id']?
try to modify #app.route as below:
#app.route('/showTable/<int:id>', methods=['DELETE'])
if still this doesn't work, you need to replace some more lines of code:
def delete_user(id):
user = Member.query.get(id)
db.session.delete(user)
db.session.commit()
return jsonify({'message': '{} has been deleted'.format(user.username)})
hope this will work

Loop through items into Django 1.8 template

I have this method:
def profile(request):
parsedData = []
if request.method == 'POST':
username = request.POST.get('user')
req = requests.get('https://api.github.com/users/' + username + '/repos')
jsonList = []
jsonList=req.json()
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
return render(request, 'app/profile.html', {'data': parsedData})
This code looks into an url like this githubtraining
As You can see, the response contains lots of repositories, however, not every github user has more than 1 repo.
Anyways, on my html view I have this:
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped tablesorter">
<thead>
<tr>
<th class="header"> Url <i class="icon-sort"></i></th>
<th class="header"> Created at <i class="icon-sort"></i></th>
<th class="header"> Updated at <i class="icon-sort"></i></th>
<th class="header"> Forks count <i class="icon-sort"></i></th>
</tr>
</thead>
<tbody>
{% for key in data %}
<tr>
<td>{{ key.html_url }}</td>
<td>{{ key.created_at }}</td>
<td>{{ key.updated_at }}</td>
<td>{{ key.forks_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
What happens then? Well, right now, if, for instance, I query the githubtraining user to see it's repos, it shows only the last one, on that and every other user, so, what am I doing wrong here? The loop is there, what am I missing?
You append data only after forloop is finished inside your view. You need to append it after each iteration instead:
for data in jsonList:
userData = {}
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
With your current code:
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
new userData overrides previous one inside for cycle. And when cycle finishing you have only one record in the list.

Django : render not passing context variable to template

I have this views function to fetch userid and accountnumber from AWS Dynamodb :
def dsctbl2(request):
dynamodb=boto3.client('dynamodb', region_name='us-west-2')
response = dynamodb.scan(
TableName='User-Account')
filtered = response['Items']
length = len(filtered)
for k in range(length):
accnum = filtered[k]['AccountNum']['S']
uid = filtered[k]['UserId']['S']
f = dict(AccountNum=accnum,userID=uid)
rows = list(f.items())
return render('useradd.html',{'rows': rows})
I have tried almost everything but the rows value is just not getting passed to my template. I even tried passing a simple string value and even that is not getting passed. This is my template table where I wish to display the userid and accountnum.
<div class="mytable">
<table>
<thead>
<tr>
<th>Account #</th>
<th>User Id</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.AccountNum }}</td>
<td>{{ row.UserId }}</td>
</tr>
{% endfor %}
</table>
</div>
When I hit the template , nothing shows up. No values are getting displayed except the table headings. Why is render not passing the context variable (list value)from my views to template ? I have been stuck with for about 6 hours ! Can someone resolve this issue ?
return render(request,'useradd.html',{'rows': rows})
you need to pass request as first parameter,

Update several records at once using Django

I want to know a way on how to update the data once is edited from the input boxes all with one click. I found this post on how to do it with checkboxes:
Updating several records at once using Django
but I'm not sure how to do it for input boxes.
here is my code:
<table class="table table-striped table-bordered table-hover dataTables-example" >
<thead>
<tr>
<th>Local</th>
<th>line</th>
<th>rack</th>
</tr>
</thead>
<tbody>
{% for linea in lineas_de_reporte %}
<tr>
<td>{{ linea.local }}</td>
<td><input type="text" name="case-opened" value="{{ linea.rack }}" id="caseOpened"/></td>
<td><input type="text" name="case-opened" value="{{ linea.line }}" id="caseOpened"/></td>
</tr>
{% endfor %}
</tbody>
Here is how it looks:
Is there a way bu just sending all the values (by id) to a function in a list using Django?
EDIT:
forms.py
class TVSForm(forms.Form):
rack = forms.CharField()
line = forms.CharField()
views.py
def search_folio(request):
if request.method == 'POST':
form = FolioSearchForm(request.POST)
if form.is_valid():
folio_number = request.POST.get('folio_number', '')
folio = 'FOLIO' + str(folio_number)
folio_query = InventoryFolioManagement.objects.filter(folio=folio)
context = {
'lineas_de_reporte': folio_query,
'folio': ' | ' + folio
}
return render(request, 'inv-search-folio.html', context)
else:
form = FolioSearchForm()
if request.GET.get('rack'):
# ... this means that user clicked on the submit button
# get the id of linea
linea_id = request.GET.get('rack-id')
new_case = request.GET.get('rack')
# fetch object from db, based on that id (aka pk)
linea = TechnicalValidationSystem.objects.get(id=linea_id)
# change its attribute to True
linea.case_opened = new_case
# update db with the new value
linea.save(update_fields=['rack'])
return render(request, 'inv-search-folio.html')

Categories