I am trying out this idea where there is a table of 'events' on a '/search' page and when a 'GO' button of an event is pressed, it will increment the 'RSVP' count of that event, and redirect back to '/search'. However, when I clicked on the 'GO' button in my application, it leads to a blank screen with url 'localhost:8080/rsvp'.
Finding it strange and wondering which part of my code is wrong. Here are some of the relevant parts of the code that I think is causing the error.
This is the code from the python file:
class RSVPItem(webapp2.RequestHandler):
# increment RSVP count when GO button is clicked
def post(self):
itemkey = ndb.Key('Items', self.request.get('itemid'))
item = itemkey.get()
item.rsvp = item.rsvp + 1
item.put()
self.redirect('/search')
# Handler for the Search page
class Search(webapp2.RequestHandler):
# Display search page
def get(self):
user = users.get_current_user()
if user: # signed in already
# Retrieve items
query = ndb.gql("SELECT * "
"FROM Items ")
template_values = {
'user_mail': users.get_current_user().email(),
'logout': users.create_logout_url(self.request.host_url),
'items': query,
}
template = jinja_environment.get_template('search.html')
self.response.out.write(template.render(template_values))
else:
self.redirect(self.request.host_url)
app = webapp2.WSGIApplication([('/', MainPage),
('/giftbook', MainPageUser),
('/wishlist', WishList),
('/deleteitem', DeleteItem),
('/search', Search),
('/rsvp', RSVPItem),
('/display', Display),
('/displaytag', Displaytag)],
debug=True)
This is from the html file for 'search.html'. Only showing the part I think is relevant.
<h4> Events List </h4>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th width="10%">Name</th>
<th>Description</th>
<th width = "10%">Link</th>
<th width = "10%">Date</th>
<th width = "10%">Type</th>
<th width = "10%">RSVP</th>
<th width = "10%">Rolling?</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.event_name }} </td>
<td>{{ item.description }}</td>
<td>{{ item.event_link}}</td>
<td>{{ item.date.strftime('%Y-%m-%d') }}</td>
<td>{{ item.event_type}}</td>
<td>{{ item.rsvp }}
<td>
<form action="/rsvp" method="post">
<input type="hidden" name="itemid" value="{{ item.item_id }}">
<input type="submit" value="GO!">
</form></td>
</tr>
{% endfor %}
</tbody>
</table>
<form action="/rsvp" method="post"> sends them to /rsvp. Do you have a url handler for /rsvp?
Make sure you cast the Key to an int:
itemkey = ndb.Key('Items', int(self.request.get('itemid')))
Instead of setting your own id item_id, just use the built-in Key:
<input type="hidden" name="itemid" value="{{ item.key.id() }}">
Check the logs to see if there are any errors.
Related
This is the page that I'm trying to work out. If the update is clicked, the filled-in details should be updated in a MySql database called TL.
But while clicking update, it's throwing the following error: AttributeError at /add/
'QuerySet' object has no attribute 'save'
The following is Views.py file in Django where I had put code for add:
def add(request):
ad = TL.objects.all()
if request.method == 'POST':
TL_Name = request.POST.get('TL_Name')
Proj_name = request.POST.get('Proj_name')
Deadline = request.POST.get('Deadline')
ad.TL_Name = TL_Name
ad.Proj_name = Proj_name
ad.Deadline = Deadline
ad.save()
return redirect("/operations")
return render(request, 'operations.html', {"name": ad, 'b': ad})
The following is the urls.py file:
from . import views
urlpatterns = [
path('', views.home),
path('adminlogin/', views.adminlogin),
path('operations/', views.operations),
path('approve/<int:pk>', views.approval),
path('decline/<int:pk>/', views.delete),
path('edit/<int:pk>/', views.edit),
path('add/', views.add),
path('tlist/', views.approved_tlist)
]
The following is the operations.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Team Leaders</title>
</head>
<body>
<h1>List of Team Leaders</h1>
<table id="table">
<tr>
<th>TL_Name</th>
<th>Proj_name</th>
<th>Proj_Status</th>
<th>Deadline</th>
<th>Action</th>
</tr>
{% for i in name %}
<tr>
<td>{{i.TL_Name}}</td>
<td>{{i.Proj_name}}</td>
<td>{{i.Proj_Status}}</td>
<td>{{i.Deadline}}</td>
<td>
Approve
Decline
Edit
</td>
</tr>
{% endfor %}
</table>
<br>
<br>
{% if a %}
<form method="post">
{% csrf_token %}
<table>
<tr>
<td>
<label>TL_Name</label>
</td>
<td>
<input type="text" name="TL_Name" value="{{a.TL_Name}}">
</td>
</tr>
<tr>
<td>
<label>Proj_Name</label>
</td>
<td>
<input type="text" name="Proj_name" value="{{a.Proj_name}}">
</td>
</tr>
<tr>
<td>
<label>Proj_Status</label>
</td>
<td>
{{a.Proj_Status}}
</td>
</tr>
<tr>
<td>
<label>Deadline</label>
</td>
<td>
<input type="text" name="Deadline" value="{{a.Deadline}}">
</td>
</tr>
<tr>
<td>
<input type="submit" value="Update">
</td>
</tr>
</table>
</form>
{% endif %}
<tr>
Add
</tr>
{% if b %}
<form method="post">
{% csrf_token %}
<table>
<tr>
<td>
<label>TL_Name</label>
</td>
<td>
<input type="text" name="TL_Name" value="{{b.TL_Name}}">
</td>
</tr>
<tr>
<td>
<label>Proj_Name</label>
</td>
<td>
<input type="text" name="Proj_name" value="{{b.Proj_name}}">
</td>
</tr>
<tr>
<td>
<label>Proj_Status</label>
</td>
<td>
{{b.Proj_Status}}
</td>
</tr>
<tr>
<td>
<label>Deadline</label>
</td>
<td>
<input type="text" name="Deadline" value="{{b.Deadline}}">
</td>
</tr>
<tr>
<td>
<input type="submit" value="Update">
</td>
</tr>
</table>
</form>
{% endif %}
</body>
</html>
Please help me to sort out this error. Thank you in advance...
ad = TL.objects.all()
is assigning the queryset of all TL to ad
ad.TL_Name = TL_Name
ad.Proj_name = Proj_name
ad.Deadline = Deadline
ad.save()
This code will not work as this isn't a single instance of a model.
If you want update all objects of TL you can use update
ad = TL.objects.update(TL_Name=TL_Name, Proj_name=Proj_name, Deadline=Deadline)
or use TL.objects.first() or TL.objects.get(id=id_you_want)
to get an individual instance of the model and then use
ad.TL_Name = TL_Name
ad.Proj_name = Proj_name
ad.Deadline = Deadline
ad.save()
You first set ad = TL.objects.all() This returns all your Model objects. Then later on in your code you're trying to save ad to your database. That won't work, and Django is telling you that. You're trying to save a queryset.
You have this error because you apply a .save() method on a queryset, that is wrong. Instead you need to call .save() on a object instance like this:
def add(request):
# ad = TL.objects.all() Not usefull here
context = {}
if request.method == 'POST':
TL_Name = request.POST.get('TL_Name')
Proj_name = request.POST.get('Proj_name')
Deadline = request.POST.get('Deadline')
# Create a new TL instance here (Note that with class.objects.create() we don't need to call save())
new_tl = TL.objects.create(TL_Name=TL_Name, Proj_name=Proj_name, Deadline=Deadline)
# Update the context data
context = ['b'] = new_tl
return redirect("/operations")
# Retrieve all TL objects and add to context
context['name'] = TL.objects.all()
return render(request, 'operations.html', context)
I was wondering if someone could help me figure out how to add rows to the following html dynamically using AJAX whenever a database query finds more records. I am using python flask and pandas to create a dataframe with nodes information such as when a node is ACTIVE, or in SLEEP mode, LOCKED or UNLOCKED. I was thinking that I could somehow pass that dataframe and iterate through it to create a table with that information and a link to another page for that specific node. Now,I think I have the first part down where I am POSTing the page when it is first brought up with all of the recorded nodes. But I think I'm doing that part wrong too. I suppose I have two questions then:
How can I pass a dataframe to the html and iterate through it correctly?
How can I use AJAX to add another row to the table whenever any other node that registers? I was thinking maybe I pass a list of nodeID's to the HTML when I POST and then have setInterval pass that to the python flask side, query the database, create a new list and compare..removing those that I already added, pass the dataframe of those that are new to AJAX function along with a full list of NodeID's....does that sound right?
So far I was only able to figure this out for a POST but no idea what to do next:
HTML
<div class="container">
<h2>Incubator List</h2>
<p>List of Registered Encubators:</p>
<table class="table table-dark table-striped">
<thead>
<tr>
<th>NodeID</th>
<th>Last Update</th>
<th>Status</th>
<th> </th>
<th>Control Link</th>
</tr>
</thead>
{% for node in nodes %}
<tr>
<td>{{ node.NodeID }}</td>
<td>{{ node.last_update }}</td>
{% if {{ node.Sleep }} == "True" %}
<td><p class="bg-secondary text-white text-center">SLEEP</p>></td>
{% else %}
{% if {{ node.Active }} == "True" %}
<td><p class="bg-success text-white text-center">ACTIVE</p></td>
{% else %}
<td><p class="bg-danger text-white text-center">NOT ACTIVE</p>></td>
{% endif %}
{% endif %}
{% if {{ node.LOCK }} == "True" %}
<i class="fas fa-lock"></i>
{% else %}
<i class="fas fa-unlock"></i>
{% endif %}
<td>
<form action="/nodeslist" METHOD = "POST">
<input type="hidden" id="NodeID" name="NodeID" value={{ node.NodeID }}>
<input TYPE="SUBMIT" value="Access" class = "btn btn-success">
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
function UPDATEnodelist(nodeIDlist) {
$.get('/nodeDHT?nodeIDlist ='+nodeIDlist ,
function(data){
const parsed = JSON.parse(data)
nodeIDlist = parsed.nodeIDlist;
something-pandas-dataframe-something;
};
)
};
setInterval(function () {
UPDATEnodelist(nodeIDlist);
return false;
}, 2500);
</script>
{% endblock content %}
python flask
#app.route('/nodeslist', methods=['POST','GET'])
def nodelist():
df= DAO.Pull_Type_Nodes()
if request.method == "POST":
title='List of Registered Nodes')
nodeIDlist = nodes.NodeID.unique()
nodes = df.to_json(orient ='records')
return render_template('nodeslist.html',title=title, nodes=nodes, nodeIDlist=nodeIDlist)
else:
oldnodeIDlist = request.form['NodeID']
add_df = df[~df['NodeID'].isin(oldnodeIDlist)]
new_nodes = add_df.to_json(orient ='records')
return new_nodes,nodeIDlist
Please any help would be greatly appreciated!
EDIT:
The response should be a dataframe with fields 'nodeID','sleep' (bool), 'lock' (bool), 'active' (bool)
<table id="table" class="table table-dark table-striped">
<thead>
<tr>
<th>NodeID</th>
<th>Last Update</th>
<th>Status</th>
<th></th>
<th>Control Link</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<form action="/nodeslist" METHOD="POST">
<input type="hidden" id="NodeID" name="NodeID" value={{ node.NodeID }}>
<input TYPE="SUBMIT" value="Access" class="btn btn-success" id="btn">
</form>
</td>
</tr>
</tbody>
</table>
const date = new Date();
const data = [...Array(10).keys()].map(id => {
return {
id: id+1,
date: new Date((Math.random() * 10000000) + date.getTime()).toLocaleString(),
status: Math.floor(Math.random() * 2),
};
});
const tbody = document.querySelector('#table').querySelector('tbody');
function test(evt) {
evt.preventDefault();
let fragment = document.createDocumentFragment();
data.forEach(d => {
let tr = document.createElement('tr');
Object.keys(d).forEach(x => {
let td = document.createElement('td');
let textNode = document.createTextNode(d[x]);
td.appendChild(textNode);
tr.appendChild(td);
})
fragment.appendChild(tr);
});
tbody.appendChild(fragment);
}
document.querySelector('#btn').onclick = test;
Here working example
I use .py code to show table in html:
#flask.route('/users_table', methods=['GET', 'POST'])
def users_table():
cur = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cur.execute('SELECT * FROM `users` WHERE isadmin = 0')
all_users = cur.fetchall()
return render_template('users-table.html', all_users=all_users
and .html code:
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>User Name</th>
<th>Email</th>
<th>Company</th>
<th>Status</th>
<th>Tools</th>
</tr>
</thead>
{% for row in all_users %}
<tr>
<td>{{row.username}}</td>
<td>{{row.email}}</td>
<td>{{row.company_name}}</td>
<td>{{row.isenabled}}</td>
<td><a href="/reset_user_pass/{{row.Id}}" data-toggle="modal" data-
target="#modaledit{{row.Id}}"><i class="fa fa-play"></i></a></td>
</tr>
{% endfor %}
</table>
show sql table
I want to change 'fa fa-play' icon based on value on 'status' column.
How can i achieve that
I guess you can use conditional statements.
<td><a href="/reset_user_pass/{{row.Id}}" data-toggle="modal" data-
target="#modaledit{{row.Id}}">
{% if row.status == 0 %}
<i class="fa fa-play"></i></a>
{% else %}
<i class="SOMETHING ELSE"></i></a>
{% endif %}
</td>
You can also checkout ternary conditions.
<i class="fa fa-{{ 'icon1' if row.isenabled else 'icon2' }}"></i>
Assuming that status value is determined based on row.isenabled, you can use inline if/else to show different icons as per the condition. I have used icon1 and icon2 which you can replace with real icons.
I'm using Flask and Jinja2 and I need to make an attendance table that includes both editable and non-editable fields. I referred to other posts such as here and here which got me to this point. The table successfully displays the editable fields using FieldList. However, I have not been able to render the non-editable fields.
This is what the table should look like:
The only fields which should be editable are "attendance code" and "comment". Unfortunately, I have not found a way to include the other fields (class name, start time, end time, first name, last name) as simple text fields.
I have tried using the read-only attribute for WTForms. While this is functional, it displays the text in text boxes which don't look appealing.
My latest attempt shown below defines a WTForms class called updateStudentAttendanceForm that inherits the fields from another class called attendanceLogClass that includes instance variables for the desired fields. I assign the values to the form class in the routes.py file. However, when I reference these variables in the html file, they result in blank fields. I have used a print statement to verify the variable assignments are working properly. I cannot figure out why the variables do not display properly when included in the html template.
forms.py
class attendanceLogClass:
def __init__(self):
self.classAttendanceLogId = int()
self.className = str()
self.firstName = str()
self.lastName = str()
self.startTime = datetime()
self.endTime = datetime()
def __repr__(self):
return f"attendanceLogClass('{self.classAttendanceLogId}','{self.className}','{self.firstName}','{self.lastName}','{self.startTime}','{self.endTime}')"
class updateStudentAttendanceForm(FlaskForm, attendanceLogClass):
attendanceCode = RadioField(
"Attendance Code",
choices=[("P", "P"), ("T", "T"), ("E", "E"), ("U", "U"), ("Q", "?"),],
)
comment = StringField("Comment")
submit = SubmitField("Submit Attendance")
class updateClassAttendanceForm(FlaskForm):
title = StringField("title")
classMembers = FieldList(FormField(updateStudentAttendanceForm))
routes.py
#app.route("/classattendancelog")
def displayClassAttendanceLog():
classAttendanceForm = updateClassAttendanceForm()
classAttendanceForm.title.data = "My class"
for studentAttendance in ClassAttendanceLog.query.all():
studentAttendanceForm = updateStudentAttendanceForm()
studentAttendanceForm.className = studentAttendance.ClassSchedule.className
studentAttendanceForm.classAttendanceLogId = studentAttendance.id
studentAttendanceForm.className = studentAttendance.ClassSchedule.className
studentAttendanceForm.startTime = studentAttendance.ClassSchedule.startTime
studentAttendanceForm.endTime = studentAttendance.ClassSchedule.endTime
studentAttendanceForm.firstName = (
studentAttendance.ClassSchedule.Student.firstName
)
studentAttendanceForm.lastName = (
studentAttendance.ClassSchedule.Student.lastName
)
studentAttendanceForm.attendanceCode = studentAttendance.attendanceCode
studentAttendanceForm.comment = studentAttendance.comment
# The following print statement verified that all of the variables are properly defined based on the values retrieved from the database query
print(studentAttendanceForm)
classAttendanceForm.classMembers.append_entry(studentAttendanceForm)
return render_template(
"classattendancelog.html",
title="Class Attendance Log",
classAttendanceForm=classAttendanceForm,
)
classattendancelog.html:
{% extends 'layout.html'%}
{% block content %}
<h1> Class Attendance </h1>
<form method="POST" action="" enctype="multipart/form-data">
{{ classAttendanceForm.hidden_tag() }}
<table class="table table-sm table-hover">
<thead class="thead-light">
<tr>
<th scope="col">Class Name</th>
<th scope="col">Start Time</th>
<th scope="col">End Time</th>
<th scope="col">First Name</th>
<th scope="col">Last Name</th>
<th scope="col">Attendance Code</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
{% for studentAttendanceForm in classAttendanceForm.classMembers %}
<tr>
<td> {{ studentAttendanceForm.className }}</td>
<td> {{ studentAttendanceForm.startTime }}</td>
<td> {{ studentAttendanceForm.endTime }}</td>
<td> {{ studentAttendanceForm.firstName }}</td>
<td> {{ studentAttendanceForm.lastName }} </td>
<td>
{% for subfield in studentAttendanceForm.attendanceCode %}
{{ subfield }}
{{ subfield.label }}
{% endfor %}
</td>
<td>
{{ studentAttendanceForm.comment(class="form-control form-control-sm") }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
Note: I haven't yet written the code to handle the form response.
I solved the problem by using the zip function to iterate simultaneously through two lists: one list with the FormField data and a second list with the non-editable "fixed field" data.
To use "zip" in the HTML template, I followed the instructions here and added this line to my init.py
app.jinja_env.globals.update(zip=zip)
updated forms.py (eliminated attendanceLogClass with fixed field variables):
class updateStudentAttendanceForm(FlaskForm):
attendanceCode = RadioField(
"Attendance Code",
choices=[("P", "P"), ("T", "T"), ("E", "E"), ("U", "U"), ("Q", "?"),],
)
comment = StringField("Comment")
submit = SubmitField("Submit Attendance")
class updateClassAttendanceForm(FlaskForm):
title = StringField("title")
classMembers = FieldList(FormField(updateStudentAttendanceForm))
updated routes.py (added new variable for fixed fields called classAttendanceFixedFields):
#app.route("/classattendancelog")
def displayClassAttendanceLog():
classAttendanceFixedFields = ClassAttendanceLog.query.all()
classAttendanceForm = updateClassAttendanceForm()
classAttendanceForm.title.data = "My class"
for studentAttendance in ClassAttendanceLog.query.all():
studentAttendanceForm = updateStudentAttendanceForm()
studentAttendanceForm.attendanceCode = studentAttendance.attendanceCode
studentAttendanceForm.comment = studentAttendance.comment
classAttendanceForm.classMembers.append_entry(studentAttendanceForm)
return render_template(
"classattendancelog.html",
title="Class Attendance Log",
classAttendanceForm=classAttendanceForm,
classAttendanceFixedFields=classAttendanceFixedFields,
)
updated classattendancelog.html (incorporated zip function in the for loop to simultaneously iterate through the editable fields and fixed fields).
{% extends 'layout.html'%}
{% block content %}
<h1> Class Attendance </h1>
<form method="POST" action="" enctype="multipart/form-data">
{{ classAttendanceForm.hidden_tag() }}
<table class="table table-sm table-hover">
<thead class="thead-light">
<tr>
<th scope="col">Class Name</th>
<th scope="col">Start Time</th>
<th scope="col">End Time</th>
<th scope="col">First Name</th>
<th scope="col">Last Name</th>
<th scope="col">Attendance Code</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
{% for studentAttendanceForm, studentFixedFields in zip(classAttendanceForm.classMembers, classAttendanceFixedFields) %}
<tr>
<td> {{ studentFixedFields.ClassSchedule.className }}</td>
<td> {{ studentFixedFields.ClassSchedule.startTime.strftime('%-I:%M') }}</td>
<td> {{ studentFixedFields.ClassSchedule.endTime.strftime('%-I:%M') }}</td>
<td> {{ studentFixedFields.ClassSchedule.Student.firstName }}</td>
<td> {{ studentFixedFields.ClassSchedule.Student.lastName }} </td>
<td>
{% for subfield in studentAttendanceForm.attendanceCode %}
{{ subfield }}
{{ subfield.label }}
{% endfor %}
</td>
<td>
{{ studentAttendanceForm.comment(class="form-control form-control-sm") }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
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.