I’m building a function which can let admin to delete account in that page.
I have several accounts in admin page but all the delete buttons are holding a value from first account in that page instead of other account.
<form action="/admin" method="post">
<table class="table">
<thead class="table-dark">
<tr>
<th>Users</th>
</tr>
</thead>
{% for user in users %}
<tr style="background-color:burlywood">
<td><input type="hidden" name="user" value="{{user.username}}">{{user.username}}</td>
<td><input type="submit" for="user" value="Delete"></td>
{% endfor %}
</tr>
</table>
#app.route("/admin", methods=["GET", "POST"])
#login_required
def admin():
"""Manage account"""
if request.method == "GET":
user_id = session["user_id"]
admin = db.execute("SELECT id FROM users WHERE id = (?)",
user_id)
for row in admin:
if int(row["id"]) == 17:
users = db.execute("SELECT username FROM users")
return render_template("admin.html", users = users)
else:
return apology("Only Admin can access this page!")
return apology("valid return")
else:
username = request.form.get("user")
flash(f"{username} has been deleted!")
return redirect("/")
I expected each delete button is holding each value in column.
After the issue is fixed, when delete button is clicked flash function will show the different username based on the value not admin at all.
here is html page
From the tags I believe you're using Jinja to load and render the html page, however, you should be more clear about what you want to ask.
This may sound like a bad idea and definitely something you shouldn't do in production but how about creating different forms for each user?
Something like this :
<table class="table">
<thead class="table-dark">
<tr>
<th>Users</th>
</tr>
</thead>
{% for user in users %}
<form action="/admin" method="post">
<tr style="background-color:burlywood">
<td><input type="hidden" name="user" value="{{user.username}}">{{user.username}}</td>
<td><input type="submit" for="user" value="Delete"></td>
</tr>
</form>
{% endfor %}
</table>
I think your line only returns usernames in your users variable:
users = db.execute("SELECT username FROM users")
So users in your template is an array that only contains a list of names, or only contains one name.
1 / Whats contains users?
2 / what if you put {{ user }} instead of {{ user.username }} in your template?
Related
I have a form in which the number of input fields keeps changing and depends on a parameter that I pass. This means that I can't go to forms.py and create a Form class because that requires me to define the input parameters beforehand.
Here is how I am defining the form.
<!-- Table to Display the original sentence and take the input of the translation -->
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Original Sentence</th>
<th scope="col">Translation</th>
</tr>
</thead>
<form name="translated-text-form" class="form-control" action="" method="post">
{% csrf_token %}
<tbody>
{% for sentence in sentences %}
<tr>
<th scope="row">{{ forloop.counter }}</th>
<td>{{ sentence.original_sentence }}</td>
<td><input type="text" name="translated-{{sentence.id}}" value="{{ sentence.translated_sentence }}" /></td>
</tr>
{% endfor %}
<tr>
<td colspan="2">
<br>
<p style="text-align: center;">
<input class="btn btn-secondary" type="submit" value="Save Translations"/>
</p>
</td>
</tr>
</tbody>
</form>
</table>
This is the form output
The user will add some text in the rightmost column and I want to save that text with a particular sentence.id in my Sentence model. This is what my model looks like
class Sentence(models.Model):
""" Model which holds the details of a sentence. A sentence is a part of a Wikipedia article which is tokenized.
Fields:
project_id: The ID of the project to which the sentence belongs
original_sentence: The original sentence tokenized from from the Wikipedia article.
translated_sentence: The translated sentence in the target language.
"""
# Define the sentence model fields
project_id = models.ForeignKey(Project, on_delete=models.CASCADE)
original_sentence = models.CharField(max_length=5000)
translated_sentence = models.CharField(max_length=5000, default="No Translation Found")
I know how I will approach this. In my views.py, I want to run a for-loop and collect the data from the form where the name is given as translated-{{sentence.id}}. However, I am not able to make the POST request handler that can directly collect the data from the form and save it in the Sentence model based on the id of the sentence. I need help in writing that request handler in my views.
I found a fix for this which doesn't use the forms.py at all. This is what the post request handler would look like.
# Handle the post request
if request.method == 'POST':
# Get the project details from the database
all_sentence_data = Sentence.objects.filter(project_id=pk)
sentence_ids = [sentence.id for sentence in all_sentence_data]
# Iterate through all the input fields in the form
for i in range(len(sentence_ids)):
# Get the translated text from the form
try:
translated_text = request.POST[f"translated-{str(sentence_ids[i])}"]
if translated_text:
# Update the Sentence object with the translated text
Sentence.objects.filter(id=sentence_ids[i]).update(translated_sentence=translated_text)
except:
continue
messages.success(request, "Your translations have been saved successfully!")
return redirect('/translation/' + str(pk)+'/')
else:
return redirect('/translation/' + str(pk)+'/')
I am developing a simple web front-end with Flask, which displays a table from database, and when an user selects a specific row, the Flask gets the information of a specific column of the selected row.
with the following codes, I display a table with 5 columns of data and one last column of 'submit' button. When the 'submit' button of the specific row, the second column ('Title') information is supposed to be posted back to Flask app.
It works 90%, because when the button is clicked, always the first row information is posted, even if a different row is selected. Could anyone figure what went wrong here?
Thanks!
here is a flask code
#app.route("/", methods=["GET", "POST"])
def home():
df = pd.read_excel('database.xlsx')
this_list = df.values.tolist()
if request.method =="POST":
if request.form.get('select_song') == 'select':
print('selected')
print(request.form.get("title"))
return render_template('basic_table.html', title='Basic Table',
table=this_list)
this is a basic_table.html
<form method="POST">
<table id="data" class="table table-striped">
<thead>
<tr>
<th>Type</th>
<th>Title</th>
<th>Location</th>
<th>Translation</th>
<th>Content</th>
<th>selection</th>
</tr>
</thead>
<tbody>
{% for row in table %}
<tr>
<td>{{ row[0] }}</td>
<td><input type="hidden" name="title" value="{{ row[1] }}"> {{ row[1] }}</td>
<td>{{ row[2] }}</td>
<td>{{ row[3] }}</td>
<td>{{ row[4] }}</td>
<td>
<input class="form__submit form__input" type="submit" value="select" name="select_song"/>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
</form>
When you click a button whose type is 'submit', it will submit the form attached to that submit button. Submitting the form means it will pass html elements by name/value pair.
In your code, you have ONLY 1 form and each row has the same input element with the name title. Therefore when you submit the form, it will submit the first instance of title
There are 2 possible solutions here
You change your code so that you have a form in each row. This way, when you submit, you are submitting the form for just that row.
You keep your code as is, but add Javascript code to 'intercept' your submit action. Your JS code will then determine which row you clicked, pick the value of the title in that row and manually submit the form with that value.
I´m new to programming, doing CS50 and currently struggling to complete the Pset9 - Finance, version from 2021. I´ve read as many threads I could find about the same issue, but none of the answers helped me to solve the problem yet.
Application.py is doing what the problem briefing required, and I passed all tests except for this one, check50 is expecting a status code 200 but I send a 400.
Check50 failed
Something to keep in mind:
Registration works as expected. I am able to register new users, and when the same username tries to register I show a 400 error.
Index function is completed, and fully functional showing all required data.
No script in Register.html to check username when pressing the submit button. I have been unable to write the right script. Not sure if this is something CS50 is expecting after all, but happy to hear anyone who has passed this test.
I would really appreciate it if someone can take a look at the code below, and let me know if I am doing something wrong or just point me in the right direction. Thanks in advance!
Here is my code for register in application.py :
#app.route("/register", methods=["GET", "POST"])
def register():
# Forget any user_id
session.clear()
# Registering a user when POST method
if request.method == "POST":
# Capturing name and password
name = request.form.get("username")
key1 = request.form.get("password")
key2 = request.form.get("confirmation")
# If fields are empty render apology
if not name:
return apology("Sorry, name is empty", 400)
elif not key1 or not key2:
return apology("Sorry, password is empty", 400)
# If keys are different render an apology
elif key1 != key2:
return apology("Sorry, passwords do not match", 400)
# Once password is valid then hash it before storing it.
key = generate_password_hash(key1, method='pbkdf2:sha256', salt_length=8)
# Checking if username exists in the database
raws = db.execute("SELECT * FROM users WHERE username = :name", name=name)
if len(raws) == 1:
return apology("Sorry, username already exists", 400)
# Include register into our database
db.execute("INSERT INTO users (username, hash) VALUES(?, ?)", name, key)
# Query again the user row, so we can pass into a session
rows = db.execute("SELECT * FROM users WHERE username = :name", name=name)
# Login the user just registered
session["user_id"] = rows[0]["id"]
# return render_template("register.html")
return redirect("/")
else:
return render_template("register.html")
Here is index in application.py :
#app.route("/")
#login_required
def index():
"""Show portfolio of stocks"""
# Query stock information from user session
stocks = db.execute("SELECT stock_symbol, stock_name, shares, value, price FROM (SELECT stock_symbol, stock_name, SUM(shares) as shares, SUM(value) as value, price FROM stocks WHERE user_id=:session GROUP by stock_symbol) WHERE shares>0", session=session["user_id"])
# Loop to sum up all stock value up
stockValue = 0
for stock in stocks:
stockValue += stock["value"]
# Query cash information from user session and send this to the html
row_cash = db.execute("SELECT cash FROM users WHERE id=:session", session=session["user_id"])
cash = row_cash[0]["cash"]
# Grand total variable adding up stock value and cash
grand_total = stockValue + cash
return render_template("index.html", stocks=stocks, cash=usd(cash), grand_total=usd(grand_total))
Here is Register.html:
{% extends "layout.html" %}
{% block title %}
Register
{% endblock %}
{% block main %}
<form action="/register" method="post">
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="username" placeholder="Username" type="text">
</div>
<div class="form-group">
<input class="form-control" name="password" placeholder="Password" type="password">
</div>
<div class="form-group">
<input class="form-control" name="confirmation" placeholder="Repeat Password" type="password">
</div>
<button class="btn btn-primary" type="submit">Register</button>
</form>
{% endblock %}
And here is index.html:
{% extends "layout.html" %}
{% block title %}
Stocks
{% endblock %}
{% block main %}
<table class="table table-striped">
<thead>
<tr>
<th>Symbol</th>
<th>Name</th>
<th>Shares</th>
<th>Price</th>
<th>Grand Total</th>
</tr>
</thead>
<tbody>
<!-- Loop through the database entries to display them in this table -->
{% for stock in stocks %}
<tr>
<td>{{ stock.stock_symbol }}</td>
<td>{{ stock.stock_name }}</td>
<td>{{ stock.shares }}</td>
<td>{{ stock.price | usd }}</td>
<td>{{ (stock.value) | usd }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>Overall stock value</td>
<td colspan=3></td>
<td>{{ "${:,.2f}".format(stocks|sum('value')) }}</td>
</tr>
<tr>
<td>CASH</td>
<td colspan=3></td>
<td>{{ cash }}</td>
</tr>
<tr>
<td colspan=4></td>
<td>{{ grand_total }}</td>
</tr>
</tfoot>
</table>
{% endblock %}
The issue was finally fixed when I deleted all my data in users.db thencheck50 passed it correctly. It seems that data was causing the whole problem, and once deleted everything got fixed.
The problem is in the index, where you query for stocks doesn't make sense to me
try using:
stocks=db.execute(
"SELECT * FROM stocks WHERE id = :user_id", user_id = session["user_id"])
It would also help if your index.html was visible
My webpage consists of 2 parts, upper part is a section that let user to enter data while bottom part displays all the data in database in a table form. When user selects "Add" button in the upper part, the data will be saved into database and being outputted in a table in bottom part of the webpage. Is there anyway to show the table once i select the "Add" button ? Right now what the code is doing is when "Add" button is being selected, it will load a new form but then the whole table will disappear. I have to manually type this address again "http://127.0.0.1:8000/hrfinance/lscholarship/" then only the table will appear. Even with refreshing the page will not work. Below is my code in
views.py:
def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
else:
form = ScholarshipForm()
id = request.GET.get('scholarship')
query_results = Scholarship.objects.all()
data = {
'query_results':query_results,
'form': form
}
return render(request, 'hrfinance/add_remove_scholarship.html', data)
models.py
class Application(models.Model):
studentID = models.CharField("Student ID", max_length=8, validators=[MinLengthValidator(8)], primary_key=True, default="")
studentName = models.CharField("Student Name", max_length=500, default="")
scholarship = models.TextField("Scholarship")
add_remove_scholarship.html
<div align="center" >
<form method="POST" onsubmit="return validation()" action="">
{% csrf_token %}
{{ form.errors }}
<p>Upload File: {{ form.doc }}</p>
<p>Faculty: {{ form.faculty }} </p>
<p>Opening date: <input id="odate" type="date" name="openDate"> </p>
<p>Closing date: {{ form.closeDate }} </p>
<input type="submit" name="AddScholarship" value="Add Scholarship" >
</form>
</div>
<br></br>
<button id="button" type="button">Delete Selected Scholarship</button>
<br></br>
{{query_results}}
<form method="POST" action="">
{% csrf_token %}
<table id="example" class="display" cellspacing="0" width="100%" border="1.5px">
<tr align="center">
<th> Scholarship </th>
<th> Faculty </th>
<th> Open Date </th>
<th> Close Date </th>
</tr>
{% for item in query_results %}
<tr align="center">
<td>{{item.doc}}</td>
<td>{{item.faculty}}</td>
<td>{{item.openDate}}</td>
<td>{{item.closeDate}}</td>
</tr>
{% endfor %}
</table>
</form>
Best practice is to use the Post/Redirect/Get pattern. This will solve your problems as well: the GET request will clear the form and show the new query results.
If the form is successfully saved, you simply return a redirect to the current page. The browser will then do a GET request. This prevents accidental duplicate form submissions when e.g. the user reloads the current page when it is still a POST request:
from django.shortcuts import redirect
def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
# Return a redirect to the same page
return redirect('/path/to/current/page/')
...
def scholarship(request, id=None):
query_results = []
if request.method == "POST":
form = ScholarshipForm(request.POST)
if form.is_valid():
scholarship = form.save(commit=False)
scholarship.save()
else:
id = request.GET.get('scholarship')
query_results = Scholarship.objects.all()
form = ScholarshipForm()
data = {
'query_results':query_results,
'form': form
}
return render(request, 'hrfinance/add_remove_scholarship.html', data)
you need to move the query out side the else condition.
Although, this method would take a lot of time as the number of rows in the database increases. A better method to do this would be to use jquery Ajax method to update the data in the database and show it dynamically using javascript/Jquery once the database is updated.
I think I may have been at it too long today and I can't wrap my head around this very well. I am fairly new to python and have been playing with flask for about a week, this is my first 'real' app that I have built so please be gentle.
The app allows an internal customer (datatechs) to enter their ticket number and login into a form. That form is submitted and kept in a sqlite DB for now, with an ID, ticket#, login, create_time and an active flag.
On another page I have what could be called a management list, this renders all the tickets that are currently in the database and marked as active. I have populated this with a jinja2 for loop and have a button that resides inline.
For example:
[ 1 ] [ ticket number ] [ login ] [ button ]
[ 2 ] [ ticket number ] [ login ] [ button ]
The button is my issue. I am very unsure about how I can have the specific button clicked cause an action against that entry in the database. I am looking to flip the status field from an int of 1 to 0 (true and false works too), so these can be essentially marked as complete but still available for analytics.
Thanks for reading, here are some snippets.
views.py
#app.route('/', methods=['GET', 'POST'])
def index():
form = TicketForm()
ticket = Ticket.query.filter_by(status=1)
if request.method == 'GET':
return render_template('index.html', form=form, ticket=ticket)
elif request.method == 'POST':
if form.validate() == False:
flash('All fields are required, please update and try again.')
return render_template('index.html', form=form, ticket=ticket)
else:
remedy = Ticket(request.form['tt'], request.form['login'], create=datetime.datetime.utcnow(), status=1)
db.session.add(remedy)
db.session.commit()
flash('Your ticket has been added to the queue')
return redirect(url_for('index'))
#app.route('/manage', methods=['GET'])
def manage():
if request.method == 'GET':
ticket = Ticket.query.all()
return render_template('manage.html', ticket=ticket)
models.py
class Ticket(db.Model):
id = db.Column(db.Integer, primary_key=True)
tt = db.Column(db.String(10))
user = db.Column(db.String(20))
create = db.Column(DateTime, default=datetime.datetime.utcnow)
status = db.Column(db.Integer)
def __init__(self, tt, user, create, status):
self.tt = tt
self.user = user
self.create = create
self.status = status
manage.html
{% extends "base.html" %}
{% block content %}
<table class="table" width=50%>
<thead>
<tr>
<th>#</th>
<th>Ticket Number</th>
<th>Requester Login</th>
<th>Time Requested (UTC)</th>
<th>Cancel Request</td>
</tr>
</thead>
<tbody>
{% for ticket in ticket %}
<tr>
<td>{{ ticket.id }}</td>
<td>{{ ticket.tt }}</td>
<td>{{ ticket.user }}</td>
<td>{{ ticket.create }}</td>
<td><button type="button" class="btn btn-xs btn-danger">Kill</button></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Generally you'd add another view to handle the flip. A note of caution is that some browser helpers preload 'normal' links on webpages to check for viruses and try helpful caching, so avoid using simple links for links that can change data. So we'll use a form instead:
change your <td><button type="button" class="btn btn-xs btn-danger">Kill</button></td> to:
<td>
<form action="{{ url_for('flip') }}" method="post">
<input type="hidden" name="flip" value="{{ ticket.id }}"/>
<input type="submit" class="btn btn-xs btn-danger" value="Kill"/>
</form>
</td>
Then add a view to do the heavy lifting:
#app.route('/flip', methods=['POST'])
def flip():
ticket = Ticket.query.filter_by(id=request.form["flip"]).first_or_404()
ticket.status = 0
db.session.commit()
return redirect(url_for('index'))
So we're just catching the id and seeing if it exists in the database, and if so, we'll flip the status to 0 and then redirect (from flask import redirect) the user back to the index view.