I'm trying to use an ajax search slice for my website that I found here: http://www.web2pyslices.com/slices/take_slice/51
But for some reason I keep getting the error:
IndexError: list index out of range
Here is my version of the code:
default.py (controller)
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
def livesearch():
partialstr = request.vars.values()[0]
query = db.listing.title.like('%'+partialstr+'%')
listings = db(query).select(db.listing.title)
items = []
for (i,listing) in enumerate(listings):
items.append(DIV(A(listing.title, _id="res%s"%i, _href="#", _onclick="copyToBox($('#res%s').html())"%i), _id="resultLiveSearch"))
return TAG[''](*items)
livesearch.html (view, which I'm {{including}} in the layout.html
<input type="text" id="search" name="search" autocomplete="off" onkeyup="getData(this.value);" /><br />
<div id="ajaxresults"></div>
db.py (model)
db.define_table(auth.settings.table_user_name,
Field('first_name'),
Field('last_name'),
Field('email'),
Field('password','password', length=512, readable=False, label='Password'),
Field('title'),
Field('photo','upload'),
Field('bio','text'),
Field('phone'), # Contact details
Field('website'),
Field('address'),
Field('registration_key', length=512,
writable=False, readable=False, default=''),
Field('reset_password_key', length=512,
writable=False, readable=False, default=''),
Field('registration_id', length=512,
writable=False, readable=False, default=''),
)
listing = db[auth.settings.table_user_name]
Any help would be very very greatly appreciated, cause I've been wracking my brains on it for days now (because I'm extremely new to programming)
Thanks!
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
You don't want to return livesearch from the index function. According to the slice you referenced, the livesearch function should be called via Ajax from your index page.
def livesearch():
partialstr = request.vars.values()[0]
I know the above line is taken directly from the slice, but a better (and more typical way) to access the value of the posted variable is:
partialstr = request.vars.partialstr if request.vars else None
Note, the above syntax will return None if there are no request.vars or if request.vars.partialstr doesn't exist, so it won't generate an error.
Also, request.vars will be None whenever there are no request variables, so you can always test for request variables with:
if request.vars:
Finally, you may be interested in web2py's built-in auto-complete widget (though I think there may be some problems with it in IE, for which a fix is in the works).
If the following is your index() code:
def index():
listings = db().select(db.listing.ALL, orderby=db.listing.first_name)
return dict(listings=listings, livesearch=livesearch())
then, if you visit index.html page and livesearch() will be called, but at this time, request.vars.values() is empty, so IndexError raised.
Don't call livesearch() in index(), and use ajax to post search word to livesearch.html, and web2py will call livesearch(), and request.vars.values()[0] is the search word.
Related
Lately I have been trying to use the GET request in django-python. However I run into a 404 error when I do so. I want the program to print the parameter given to it.
URL PATTERN :
path('add<int:hello>/',views.add,name = 'Add')
VIEWS.PY:
def add(request,num1):
val1 = request.GET["num1"]
return HttpResponse(request,"Hello")
WHAT I AM SEARCHING ON BROWSER:
http://127.0.0.1:8000/add?1
A couple of things are strange or broken here.
Given path('add<int:hello>/', views.add, ...),
Django expects that function views.add has the following signature:
def add(request, hello):
The pattern 'add<int:hello>/' expects urls with "add" followed by an integer, such as:
http://127.0.0.1:8000/add1
http://127.0.0.1:8000/add2
http://127.0.0.1:8000/add3
...
and so on.
request.GET["num1"] expects urls that have num1=... in their query string, such as:
http://127.0.0.1:8000/add1?num1=...
HttpResponse expects a string type as its first parameter,
not an HttpRequest type as in the posted code.
Fixing the problems
This might be close to what you want, and it will work:
path('add<int:num1>/', views.add, name='Add')
def add(request, num1):
return HttpResponse(f"Hello {num1}")
# visit http://127.0.0.1:8000/add1
Another variation:
path('add', views.add, name='Add')
def add(request):
num1 = request.GET['num1']
return HttpResponse(f"Hello {num1}")
# visit http://127.0.0.1:8000/add?num1=123
http://127.0.0.1:8000/add?hello=1
This should work. you need to add the query param name as well.
To get the value you need to use this code:
request.GET["hello"]
I have a Python flask application which takes input id's and dynamically generates data into a html file. Below is my app.py file.
#app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == 'POST':
id = request.form['item_ids']
list = [id]
script_output = subprocess.Popen(["python", "Search_Script.py"] + list)
# script_output = subprocess.call("python Search_Script.py "+id, shell=True)
# render_template('running.html')
script_output.communicate()
#driver = webdriver.Chrome()
#driver.get("home.html")
#driver.execute_script("document.getElementById('Executed').style.display = '';")
return render_template('execute.html')
#app.route('/output')
def output():
return render_template('output.html')
output.html file has below code at the bottom.
<div class="container" style="text-align: center;">
{% include 'itemSearchDetails.html' %}
</div>
itemSearchDetails.html is generated every time dynamically based on the input. I check for different inputs and it is generating perfectly. When I run it with some input(assume 2) values for the first time, it runs perfectly and shows the output correctly. But, when I run for different values(assume 4) for the next time, the file 'itemSearchDetails.html' is generated for those 4 values but the browser only shows output for the first 2 values. No matter how many times I run it, browser shows only output with the first run values.
So, every time only the first inputted values are shown no matter how many times I run. I am not sure if it is browser cache issue since I tried "disabling cache" in chrome. Still it didn't work. Please let me know if there is something I am missing.
Try solution from this answer:
Parameter TEMPLATES_AUTO_RELOAD
Whether to check for modifications of the template source and reload
it automatically. By default the value is None which means that Flask
checks original file only in debug mode.
Original documentation could be found here.
Looks like Jinja is caching the included template.
If you don't need to interpret the HTML as a Jinja template, but instead just include its contents as-is, read the file first and pass the contents into the template:
with open('itemSearchDetails.html', 'r') as infp:
data = infp.read()
return render_template('execute.html', data=data)
...
{{ data|safe }}
(If you do need to interpret the HTML page as Jinja (as include will), you can parse a Jinja Template out of data, then use the include tag with that dynamically compiled template.)
I've been reading the book 'Head First Python' where the writer talks about creating dynamic webpages using a module he created called 'yate', an HTML template engine (which I renamed to site_yate in the code below). The example he works through is a hypothetical coach wanting his athletes to be able to check their times online. The design is as follows: first you enter the homepage which has a link to run a script which generates a webpage where you can select the athlete whose times you want to view. Then when you select your athlete and click submit the form calls another script called "site_generate_timing_data.py" where you can views the athlete's top times. So I decided to take it further and add functionality to add a time for the athlete, using this extra line of code in my python script.
print(site_yate.do_form("addtime.py", [athlete_id]))
The HTML this will generate will be this:
<form action="addtime.py" method="POST">
<h1>Want to add a time?</h1>
<input type="Text" name="1" size=40> //"1" is the athlete's id in this example
<input type="Submit" value="Submit">
</form>
As you can see this code calls the script 'addtime.py' which has the following code:
import cgi
import sqlite3
data = cgi.FieldStorage().value[0] #this attribute will be in the form MininFieldStorage(name, value)
id = data.name #this attribute is the input's name i.e. athlete's id
time = data.value #this attribute is the input's value i.e. the time
connection = sqlite3.connect("NUACDB.sqlite") #my DB's name
cursor = connection.cursor()
cursor.execute("""INSERT INTO timing_data (athlete_id, time)
VALUES (?, ?)""",
(id, time)) #just SQL stuff
connection.commit()
connection.close()
Which works fine, however I want to change a few thing about this, since it leaves the user on a blank page. I could generate some HTML code to provide links to the homepage etc. or even JavaScript code to redirect the user automatically, but I want to keep this script HTML-free so that I can also use it elsewhere.
What I want to do instead is make the script execute on the same page. Not only that, but I would also prefer if I could put the addtime.py code as a function in another module called 'athletemodel.py' and call it form there, i.e. athletemodel.addtime() (or I could do from athletemodel import addtime so I can call the function directly). How can I call a python function using HTML code? I'm aware of the onsubmit="" form attribute but apparently that is for JavaScript functions. Another thing I'm unsure about is whether the data submitted in the form will still be accessible through CGI FieldStorage and hence whether my addtime.py code will still work as it is.
This stuff is so confusing! All help is appreciated.
Not sure if you already had it in mind, but I would use ajax (remember to include the jQuery library). Here's a rough example to get you started if this is what you want. It'll keep them on the same page:
JavaScript file:
$('#submitButtonId').click(function (event) {
event.preventDefault();
$('#submitButtonId').hide();
$('#thinking').show(); //some div with a nice ajax loader gif...
$.ajax({
type: 'POST',
data: $('#formId').serialize(),
url: '/URL_path_to_function',
success: function (data) {
$('#loading').hide();
var response = data.result //now do stuff with your response
}
error: function(error){
console.log('Error')}
});
Python view/function:
import jsonify
if request.method == 'POST':
value = request.form['input value'] #flask...
#Do stuff
return jsonify(result='Some response')
I'm trying to use create_logout_url to create a sort of admin menu in a trivial appengine-site, but it is currently behaving quite wierdly. Take a look at the code below:
menu = []
logout_link = "<a href='%s'>Log out</a>" % users.create_logout_url('/blog')
menu.append(logout_link)
new_entry = ''
if users.is_current_user_admin():
new_entry = "<a href='%(newpost)s'>New entry</a>" % {'newpost': self.uri_for('blog_entry')}
menu.append(new_entry)
return ','.join(menu)
The expected output should be something like:
<a href='/_ah/login?continue=http%3A//localhost%3A8080/blog&action=Logout'>Log out</a>,<a href='/blog/newpost'>New entry</a>
But it's actually:
Log out
Any ideas?
Update
I'm trying to use the above code in my base handler (which contains a lot of code that gets reused everywhere, like this admin menu and templating functions), if it helps or matters.
Changing the logout_link-part to:
logout_link = users.create_logout_url('/blog')
Results in the following output:
Log out
(I'd already tried that before, however, but to no avail)
Monotux, could you provide us with some more details about your code. You said you are using some other menus and templating functions.
The snippet provided generates the correct code:
<a href='/_ah/login?continue=http%3A//localhost%3A8080/blog&action=Logout'>Log out</a>,<a href='/blog/newpost'>New entry</a>
And given the two outputs you are seeing:
Log out
Log out
wich both are of the form
<a href='...'>Log out</a>
I think you are embedding the response of the snippet in some other code.
So, I'm trying to make a simple call using jQuery .getJSON to my local web server using python/django to serve up its requests. The address being used is:
http://localhost:8000/api/0.1/tonight-mobile.json?callback=jsonp1290277462296
I'm trying to write a simple web view that can access this url and return a JSON packet as the result (worried about actual element values/layout later).
Here's my simple attempt at just alerting/returning the data:
$.getJSON("http://localhost:8000/api/0.1/tonight-mobile.json&callback=?",
function(json){
alert(json);
<!--$.each(json.items, function(i,item){
});-->
});
I am able to access this URL directly, either at http://localhost:8000/api/0.1/tonight-mobile.json or http://localhost:8000/api/0.1/tonight-mobile.json&callback=jsonp1290277462296 and get back a valid JSON packet... So I'm assuming it's in my noob javascript:)
My views.py function that is generating this response looks as follows:
def tonight_mobile(request):
callback = request.GET.get('callback=?', '')
def with_rank(rank, place):
return (rank > 0)
place_data = dict(
Places = [make_mobile_place_dict(request, p) for p in Place.objects.all()]
)
xml_bytes = json.dumps(place_data)
xml_bytes = callback + '(' + xml_bytes + ');'
return HttpResponse(xml_bytes, mimetype="application/json")
With corresponding urls.py configuration:
(r'^tonight-mobile.json','iphone_api.views.tonight_mobile'),
I am still somewhat confused on how to use callbacks, so maybe that is where my issue lies. Note I am able to call directly a 'blah.json' file that is giving me a response, but not through a wired URL. Could someone assist me with some direction?
First, callback = request.GET.get('callback=?', '') won't get you the value of callback.
callback = request.GET.get( 'callback', None )
Works much better.
To debug this kind of thing. You might want to include print statements in your Django view function so you can see what's going on. For example: print repr(request.GET) is a helpful thing to put in a view function so that you can see the GET dictionary.