Django: Receiving data from dynamic form value field - python

Working on converting an app from Flask to Django and getting stuck on how I can pull data from the value of a form button. I have some data that is rendered in a table with a for loop. Each entry has a button displayed that allows my to flip an integer field for the rendered data. Once it's flipped, it's no longer listed.
# manage.html
{% for ticket in tickets %}
<tr>
<td>{{ my_obj.id }}</td>
<td>{{ my_obj.tt }}</td>
<td>{{ my_obj.user }}</td>
<td>{{ my_obj.time }}</td>
<td><form action="/flip/" method="post">{% csrf_token %}
<input type="hidden" name="flip" value="{{ my_obj.id }}"/>
<input type="submit" class="btn btn-xs btn-danger" value="Kill"/>
</form>
</td>
</tr>
{% endfor %}
# views.py
def flip(request):
if request.method == 'POST':
tt_id = request.POST.get('value')
return HttpResponse(tt_id )
def manage(request):
my_obj = MyObject.objects.filter(status=1)
return render(request, 'manage.html', {'my_obj': my_obj})
Currently I am getting a response of None rather than the actual ID which is showing in the value field with firebug.
Thanks for looking!

You have to access the fields by the name, not with value. e.g.
request.POST.get('flip')
If you want to access the buttons value, you need to set the name attribute on it.
For details on your request it is helpful for print or return the whole request object. A debugger would be an other way to take a look at it.

Related

How to receive a row information from a HTML table to Python Flask

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.

Flask - cant post to route [duplicate]

This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Closed last year.
I'm creating a configurator app for heating systems. Essentially the idea is by putting in a few inputs - the app will spit out the part number for a system pack where a user can see a detailed bill of material (BOM).
One key element is the output where we need to show a few options. I.e. if someone needs a 200kW system, there could be 3-4 packs that are suitable (190kW -210kW might be more cost effective).
I want in the first instance to show on a route the pack options that are suitable- then the user selects the pack they want- which takes you to a route (/cart) which shows the BOM.
I have put in input variables min and max which searches a database cascades.db. This successfully shows me the table of options.
from cs50 import SQL
from flask import Flask, render_template, request, url_for, redirect
app = Flask(__name__)
db = SQL("sqlite:///cascades.db")
#app.route("/")
def index():
return render_template("index.html")
#app.route("/search", methods=["GET", "POST"])
def search():
output = request.form.get("output")
hydraulic = request.form.get("hydraulic")
layout = request.form.get("layout")
controls = request.form.get("controls")
min_output = int(output) - 15
max_output = int(output) + 15
cascades = db.execute("SELECT * FROM cascades WHERE hydraulic = ? AND layout = ? AND output BETWEEN ? and ?", hydraulic, layout, min_output, max_output)
return render_template("search.html", cascades=cascades)
#app.route("/cart", methods=["GET", "POST"])
def cart():
bom_id = request.form.get("bom_id")
bom = db.execute("SELECT * FROM bom WHERE bom_id = ?", bom_id)
return render_template("bom.html", bom = bom)
When running the app- the first bit works - i.e. it shows me a list of all the packs that meet the criteria- but when clicking the 'Choose' button Im getting stuck.
{% extends "layout.html" %}
{% block body %}
<h3> Boiler Cascade Pack Options:</h3>
<table class="table table-striped table-boardered">
<tr>
<th>Part Number</th>
<th>Description</th>
<th>Number of boilers</th>
<th>BOM</th>
</tr>
{% for cascades in cascades %}
<tr>
<td scope="cascades">{{ cascades["id"] }}</td>
<td>{{ cascades["description"] }}</td>
<td>{{ cascades["number_of_boilers"] }}</td>
<td>
<form action "/cart" method="post">
<input name="bom_id" type="hidden" value="{{ cascades["id"] }}">
<input class="btn btn-primary" type="submit" value="Choose">
</form>
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
But when submitting the form- where they select the pack (which has the pack id number- as a hidden form) I get the following error:
File "/home/ubuntu/cascade2/application.py", line 26, in search
min_output = int(output) - 15 TypeError: int() argument must be a
string, a bytes-like object or a number, not 'NoneType'
It seems like the route is trying to use the same logic in the second search but at this point its redundant. The second search all I want is to show me information where the Pack id = BOM.
I've noticed the URL stays on the (/search) route with this and not going to the (/cart).
I've tried several things such as putting in a IF NOT output- redirect to Cart to try and bi pass this- which successfully loads the bill of material page but nothing comes up as I don't think its posted the id to the route.
I've also changed it to GET instead of POST, which results in the query string /search?bom_id=71723827132. Which shows its picking up the part number- but staying on the /search route where I see the error.
<h3> Boiler Cascade Pack Options:</33>
<table class="table table-striped table-boardered">
<tr>
<th>Part Number</th>
<th>Description</th>
<th>Number of boilers</th>
</tr>
{% for cascade in cascade %}
<tr>
<td scope="cascade">{{ cascades["id"] }}</td>
<td>{{ cascades["description"] }}</td>
<td>{{ cascades["number_of_boilers"] }}</td>
</tr>
{% endfor %}
</table>
<br>
<h4>Bill of material:</h4>
<br>
<table class="table table-striped table-boardered">
<tr>
<th>Product ID</th>
<th>Product Description</th>
<th>Quantity</th>
</tr>
{% for bom in bom %}
<tr>
<td scope="bom">{{ bom["part_number"] }}</td>
<td>{{ bom["product_description"] }}</td>
<td>{{ bom["quantity"] }}</td>
</tr>
{% endfor %}
</table>
Been stuck on this for a month. This to me is the last piece of the puzzle. Any help/suggestions would be great. I'm new to programming so I bet I've missed something obvious :)
Your <form action "/cart" method="post"> is missing an = after action. That means the action attribute is not properly defined, and the default for action always is the URL you're currently on. That's why it stays at /search.

CS50(2021) - Finance. :( registration rejects duplicate username - expected status code 200, but got 400

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

Form initiates POST request for all but one case

I'm building a simple web app that displays the logged-in users hardware asset register of sorts. In my Html page I have an accordion with a table as follows:
<tbody>
{% for hard in HARDWARE %}
<tr>
<td>
<form action="{{url_for('del_hardware', id=hard.id)}}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</td>
<td>{{ hard.name }}</td>
<td>{{ hard.description }}</td>
<td>{{ hard.purchased }}</td>
</tr>
</tbody>
{% endfor %}
in my application.py file I then have the following code:
#app.route('/del_hardware/<string:id>', methods=["POST"])
#login_required
def del_hardware(id):
db.execute("UPDATE hardware SET actioned ='D' WHERE id=:hid", hid=id)
return redirect("/")
for whatever reason, the route does not work for the first record in the table.
Clicking the Delete button for the first record in the table:
No request is shown, the page reloads or is redirected to "/".
Clicking the Delete button for every other record in the table: I get the following request
INFO:werkzeug:...[23/Dec/2019 10:31:42] "POST /del_hardware/4 HTTP/1.0" 302 -
where 4 is the ID of the device in the hardware table, and it works fine - The SQL
statement is executed and I'm redirected to "/" as intended.
Any help would be appreciated, apologies if I haven't described the issue that well or if i've simply overlooked a silly mistake somewhere.

Django: writing a view to delete multiple object with checkboxes

So I have a table that lists all the record from my model.
But now I'm trying to make a Checkbox and delete it (kinda like the Django admin way), I can't find the documentation for this , as I'm sure there are several ways to to this.
But I'm trying to figure out like whats the proper way for doing this , should I do this via view ?
How to create single delete button for multiple delete instances in html and view.I am not using form
I refreed this side but not get correct solution
Django: writing a view to delete an item with checkboxes
Deleting multiple rows in Django frontend
list.html
{% for obj in object_list %}
<tbody>
<tr>
<td><input type="checkbox" name="data" value="{{obj.id}}" ></td>
<td><a href='#' data-toggle="collapse" value="{{obj.id}}">{{ obj.id }}</td>
<td>{{ obj.Full_Name }}</td>
<td>{{ obj.Agency_Name}}</td>
<td>{{ obj.Date_of_Birth}}</td>
<td>{{ obj.Agency_Code}}</td>
<td><span class="label label-primary">{{ obj.Agent_Status}}</span></td>
<td class="text-right">
<i class="fa fa-list-alt" aria-hidden="true"></i>
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
#<i class="fa fa-trash" aria-hidden="true"></i>
#Remove this button and create single button for multiple delete
</td>
</tr>
</tbody>
{% endfor %}
view.py
def Agent_List(request, id=None): #list items
queryset = Agent.objects.order_by('id')
#queryset = Agent.objects.all()
query = request.GET.get('q')
if query:
queryset=queryset.filter(
Q(Aadhaar_Number__icontains=query) |
Q(PAN_Number__icontains=query) |
Q(Account_Number__icontains=query)
).distinct()
context = {
"object_list": queryset,
"Full_Name ": "Agent_List",
}
return render(request, "customer/Agent_List.html", context)
def Agent_Delete(request, id=None):
instance = get_object_or_404(Agent, id=id)
instance.delete()
messages.success(request, "Successfully deleted")
return redirect("customer:Agent_List")
In def Agent_Delete(request, id=None) it delete single id.but How to delete selected multiple id.Thank you in advance.

Categories

Resources