Okay so I have the following HTML form:
<form method ="post" action="/custom">
<div class="container">
<select multiple name ="multiple">
<option value="id">ID</option>
<option value="is_visible">Visible</option>
</select>
<button type="submit">Login</button>
</div>
</form>
And I have the following Python code to insert values in to the database
#app.route('/custom',methods = ['POST', 'GET'])
def custom_fields():
login = 'urlhere.com'
url_tags = 'targeturlhere.com/page.json'
multiple = request.form.getlist('multiple')
post = session.post(login, data=payload)
r_tags = session.get(url_tags)
parsed_tags = json.loads(r_tags.text)
for tag in parsed_tags['tags']:
cursor.execute("INSERT INTO dbo.tags"
"(tagid, is_visible, products_count, slug, title, created_at ,updated_at )"
"VALUES (?,?,?,?,?,?,?)"
,(tag[multiple[0]],tag[multiple[1]], tag['products_count']
,tag['slug'],tag['title'],tag['created_at'],tag['updated_at']))
con.commit()
So what I do now is to select the values that I want to pass to the Python code. My problem now is that if I choose the values that the code is working, but if I don't choose something I get the following:
IndexError: list index out of range
Is there any possible way to pass empty values and to accomplish what I want? Also note that I am working with json code, see a format below:
{
tags: [
{
created_at: "2018-02-28T14:55:19+01:00",
customer_id: null,
id: 4544544,
is_visible: true,
products_count: 6,
slug: "productname",
title: "productname",
updated_at: "2018-05-25T00:08:04+02:00"
},
],
}
I'm assuming you are passing an empty value for the multiple key. The simplest solution would be to check the contents of the multiple list right after taking it from the request. If it is empty, use a default one:
multiple = request.form.getlist('multiple')
if not multiple or len(multiple) < 2:
multiple = ['default_tag', 'default_is_visible']
Related
I have a Django Filter that that has 4 choices. I would like to order these choices on the template in the order that I have written them in the filter.
filter.py:
RarityChoices = {
('common', 'Common'),
('uncommon', 'Uncommon'),
('rare', 'Rare'),
('mythic', 'Mythic')
}
rarity = ChoiceFilter(field_name='rarity', empty_label='Any', choices=sorted(RarityChoices), widget=RadioSelect())
template.html:
<div>
<label class="mb-1" for="id_type">Rarity:</label>
{{ card_filter.form.rarity}}
</div>
Screenshot:
If I change my filter to:
rarity = ChoiceFilter(field_name='rarity', empty_label='Any', choices=RarityChoices, widget=RadioSelect())
The filter looks like this on the template:
Neither are in the order that I want or in the order listed in the filter.py file.
RarityChoices = {
('common', 'Common'),
('uncommon', 'Uncommon'),
('rare', 'Rare'),
('mythic', 'Mythic')
}
is a set ... sets are unordered ... change it to a list or a tuple
RarityChoices = [ # [ is for list
('common', 'Common'),
('uncommon', 'Uncommon'),
('rare', 'Rare'),
('mythic', 'Mythic')
]
I 'ld like for a user to drop a random search in a search form for a book title and find get results if the book is in the db. Below is part of the code block.
I 'm having some issues searching for a single document in my mongodb using a search field and search strings. Below is the code. I'm trying to get the search result via the find_book route.
The code above with the /find_book/<book_id> returns errors.
Below is a part of my code in the app.py file and the search form.
I get the following errors.
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'find_book'. Did you forget to specify values ['book_title']?
Traceback (most recent call last)
# create an instance of py_mongo with app as argument
mongo = PyMongo(app)
#app.route('/')
def home():
return render_template('home.html')
# define the various menu options
#app.route('/get_books')
def get_books():
return render_template('books.html', books=mongo.db.books.find())
# Add a book
#app.route('/add_book')
def add_book():
return render_template('add_book.html',
faculties=mongo.db.faculties.find())
# Add submit button for Books
#app.route('/insert_book', methods=['POST'])
def insert_book():
book = mongo.db.books
book.insert_one(request.form.to_dict())
return redirect(url_for('get_books'))
# wire the edit button
#app.route('/edit_book/<book_id>')
# description task, name, due date, is urgent fields will be
# pre-populated based on the information returned in the task.
def edit_book(book_id):
a_book = mongo.db.books.find_one({"_id": ObjectId(book_id)})
# category names will be prepolulated based on the collection
# # of categories returned in the categories cursor
all_faculties = mongo.db.faculties.find()
return render_template('edit_book.html',
book=a_book, faculties=all_faculties)
#app.route('/update_book/<book_id>', methods=['POST'])
def update_book(book_id):
# access the database collection
book = mongo.db.books
# call the update function, specify an id
book.update({'_id': ObjectId(book_id)},
{
'faculty_name': request.form.get('faculty_name'),
'subject_name': request.form.get('subject_name'),
'book_title': request.form.get('book_title'),
'book_author': request.form.get('book_author'),
'book_description': request.form.get('task_description'),
'lender_name': request.form.get('lender_name'),
'due_date': request.form.get('due_date'),
'is_available': request.form.get('is_urgent')
})
return redirect(url_for('get_books'))
# specify the form fields to match the keys on the task collection
# delete a book
#app.route('/delete_book/<book_id>')
def delete_book(book_id):
mongo.db.books.remove({'_id': ObjectId(book_id)})
return redirect(url_for('get_books'))
# find a book by text search
#app.route('/find_book/<book_title>', methods=['GET'])
def find_book(book_title):
book_title = mongo.db.books
book_title.find_one(
{
'book_title': request.form.get('book_title'),
})
return render_template('find.html', book_title=book_title)
# categories function
#app.route('/get_faculties')
def get_faculties():
return render_template('faculties.html',
faculties=mongo.db.faculties.find())
if __name__ == '__main__':
app.run(host=os.environ.get('IP'),
port=int(os.environ.get('PORT')),
debug=True)
<form action="{{ url_for('find_book') }}" method="GET">
<input type="text" placeholder="Book Title" id="book_title" name="book_title" >
<button type="submit"><i class="fa fa-search">Search</i></button>
</form>
Your find_book route is expecting an argument book_title
But you are not passing that in {{ url_for('find_book') }}
You could just change this route to #app.route('/find_book') and get the value from request.form or if you are using this route in another place of your application you could use the approach from this question and use this way:
#app.route('/find_book/', defaults={'book_title': None})
#app.route('/find_book/<book_title>')
def find_book(book_title):
books = mongo.db.books
if book_title is None:
book_title = request.form.get('book_title')
book = books.find_one({
'book_title': book_title
})
return render_template('find.html', book=book)
I could not run this snippet of code now, so let me know if dont work.
I have a two dictionaries with several keys and one value for each key. One dict has weekly cumulative work hours, the other weekly cumulative overtime hours. The key is a datetime object, which is calculated to be the beginning of a week. On my webpage I have a dropdown box, which contains the week beginnings
<form action="{{ url_for('index') }}" method="post">
<select class="form-control" name="cumuls" id="select1" onchange="if(this.value != 0) { this.form.submit(); }">
<option value="0">Cumulative for week beginning...</option>
{% for i,j in zip(wks, wks2) %}
<option value="{{ i }}">{{ j }}</option>
{% endfor %}
</select>
</form>
(wks2 is just a nicely formatted version of wks, and wks is just a list of the keys from the dicts which are datetime objects (the dictionaries have the same keys))
I want to be able to click on an option from the dropdown box and for the corresponding values from the two dictionaries to appear below the dropdown box.
I handle the form here (within an index() function), after the if is the end of the index function:
if request.method == 'POST':
if 'cumuls' in request.form:
week_Begin = request.form['cumuls']
listHours = listDates(current_user.get_id())
dct_hours, dct_overtime, wks = weeklySum2(listHours)
#strfdelta is a custom function that formats timedeltas
cumul_hrs = strfdelta(dct_hours[datetime.fromisoformat(week_Begin)], '%H:%M')
cumul_overtime = strfdelta(dct_overtime[datetime.fromisoformat(week_Begin)], '%H:%M')
return redirect(url_for('index'))
listHours = listDates(current_user.get_id())
dct_hours, dct_overtime, wks = weeklySum2(listHours)
print(wks)
# wkbgn = weekbeginning, this just formats the dates nicely
wks2 = [wkbgn.strftime('%A') + ' ' + wkbgn.strftime('%-d') + ' ' + wkbgn.strftime('%b') + ' ' + wkbgn.strftime('%Y') for wkbgn in wks]
currentDay = datetime.today()
start_week = (currentDay - timedelta(days=currentDay.weekday()))
return render_template('index.html', form=form, hoursDb = listHours, dct_overtime=dct_overtime,dct_hours=dct_hours, wks=wks, wks2=wks2, zip=zip)
So within the if 'cumuls'..., I basically get the cumulative working and overtime hours for the selected week, in cumul_hrs and cumul_overtime, which works. I essentially want these variables to be displayed on the webpage (below the dropdown box), and the default variable that is displayed will be the current weeks cumulative so far. How could I do this?
Any pointers/tips are greatly appreciated.
I ended up just changing the redirect within the elif statement to
return redirect(url_for('index', cumul_hrs=cumul_hrs, cumul_overtime=cumul_overtime))
and then getting the variables from the URL with:
cumul_hrs, cumul_overtime = request.args.get('cumul_hrs'), request.args.get('cumul_overtime')
and passing them through render_template.
I am trying to return a python dictionary to the view with AJAX and reading from a JSON file, but so far I am only returning [object Object],[object Object]...
and if I inspect the network traffic, I can indeed see the correct data.
So here is how my code looks like. I have a class and a method which based on the selected ID (request argument method), will print specific data. Its getting the data from a python discretionary. the problem is not here, have already just tested it. But just in case I will link it.
# method to create the directionary - just in case #
def getCourselist_byClass(self, classid):
"""
Getting the courselist by the class id, joining the two tables.
Will only get data if both of them exist in their main tables.
Returning as a list.
"""
connection = db.session.connection()
querylist = []
raw_sql = text("""
SELECT
course.course_id,
course.course_name
FROM
course
WHERE
EXISTS(
SELECT 1
FROM
class_course_identifier
WHERE
course.course_id = class_course_identifier.course_id
AND EXISTS(
SELECT 1
FROM
class
WHERE
class_course_identifier.class_id = class.class_id
AND class.class_id = :classid
)
)""")
query = connection.engine.execute(raw_sql, {'classid': classid})
for column in query:
dict = {
'course_id' : column['course_id'],
'course_name' : column['course_name']
}
querylist.append(dict)
return querylist
my jsonify route method
#main.route('/task/create_test')
def get_courselist():
#objects
course = CourseClass()
class_id = request.args.get('a', type=int)
#methods
results = course.getCourselist_byClass(class_id)
return jsonify(result=results)
HTML
and here is how the input field and where it should link the data looks like.
<input type="text" size="5" name="a">
<span id="result">?</span>
<p>click me
and then I am calling it like this
<script type=text/javascript>
$(function() {
$('a#link').bind('click', function() {
$.getJSON("{{ url_for('main.get_courselist') }}", {
a: $('input[name="a"]').val()
}, function(data) {
$("#result").text(data.result);
});
return false;
});
});
</script>
but every time I enter a id number in the field, i am getting the correct data. but it is not formatted correctly. It is instead printing it like [object Object]
source, followed this guide as inspiration: flask ajax example
The data return by your server is like: {result: [{course_id: 'xxx', course_name: 'xxx'}]}, in which data.result is a JS Array.
when you set it to $("#result").text(), JS convert a array to string, so the result is [object Object].
You should iterate over the array to construct a string, then set the string in DOM, like:
courseStr = data.result.map(function(course) {return course.course_id + '-' + course.course_name; }).join(',');
$("#result").text(courseStr);
The API description for flask.json.jsonify indicates it's expecting keyword parameters. What you actually want to do seems to be serialize a list object containing dictionaries, have you tried flask.json.dumps instead? Assuming you've got the dumps symbol imported, instead of your jsonify call you can try:
return dumps(results)
I have a Python script creating a dictionary and passing it to a html page to generate a report.
in Python:
data_query= {}
data_query["service1"] = "value1"
data_query["service2"] = "value2"
return data_query
in HTML:
% for name, count in data_query:
<tr>
<td>${name}</td>
<td>${count}</td>
</tr>
% endfor
it does not work, says that it does not return enough values.
I also tried (pointed out in a comment in the other question, that I deleted by mistake):
% for name, count in dict.iteritems():
It does not give any error, but does not work. Displays nothing.
${len(dict)}
gives the right dictionary length
${len(dict.iteritems())}
does not display anything and seem to have a weird effect on my table format.
Is there a way to iterate correctly a dictionart in HTMl to display both the key and value?
EDIT: How I transfer the dictionary to the html page.
from mako.lookup import TemplateLookup
from mako.runtime import Context
from mako.exceptions import text_error_template
html_lookup = TemplateLookup(directories=[os.path.join(self.dir_name)])
html_template = html_lookup.get_template('/templates/report.html')
html_data = { 'data_queries' : data_queries }
html_ctx = Context(html_file, **html_data)
try:
html_template.render_context(html_ctx)
except:
print text_error_template().render(full=False)
html_file.close()
return
html_file.close()
% for name, count in dict.items:
<tr>
<td>${name}</td>
<td>${count}</td>
</tr>
% endfor
should probably work ... typically you dont call the fn when you pass it to a templating language... alternatively
% for name in dict:
<tr>
<td>${name}</td>
<td>${dict[name]}</td>
</tr>
% endfor
would likely also work
as an aside ... dict is a terrible variable name as it shadows the builtin dict (which might be part of your problem if that is actually your variable name)