I'm going through Miguel Grinbergs Flask book and at one point he uses the following line:
request.endpoint[:5] != 'auth.'
I know [:5] is a slice operation, but I'm not sure why it is being used here. What does the list consist of that we only want elements 0-5?
What does the list consist of that we only want elements 0-5?
To be precise, request.endpoint is not a list, it's a string. And it doesn't matter what the rest of it contains, the code is only concerned with it beginning with 'auth.':
('auth.somethingsomething'[:5] == 'auth.') is True
request.endpoint is the name the current view function was registered as, for example auth.login is the name of the def login(): view. Views that have a prefix like prefix. were registered on a blueprint, which groups related views. So the code is checking if the current view being handled is part of the auth blueprint.
If you're curious about what value it contains, you can add a debugging breakpoint to the code and inspect it:
# ... previous app code ...
import pdb; pdb.set_trace()
request.endpoint[:5] != 'auth.'
Then run and test the code. When it hits that point, it'll pause execution and give you a pdb shell, which will let you look at the request object and its endpoint attribute.
you can checking on terminal by
venv $ python manage.py shell
import flask from request
print(request.endpoint)
Related
Background/Goal
I'm trying to create a study prep website and as part of it I would like to initialize a database labelled "Topic" with some default values. The contents of this table are just meant to be initialized once when the database is first created. I'm using Flask and SQLAlchemy for this project.
The Problem
I've tried to achieve this by defining a function like so (Note: The "..." mark pieces of code present which I believe aren't very relevant to this problem. If you feel like I'm likely leaving out something important, please inform me)
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = "hwiu2222"
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{DB_NAME}"
db.init_app(app)
...
from .models import User, Topic
create_database(app)
...
#listens_for(Topic.__table__, "after_create")
def insert_topics(*args, **kwargs):
topics = (genfromtxt("src/static/topics.csv", delimiter=',', skip_header=1, dtype=None)).tolist()
for topic in topics:
new_topic = Topic(title=topic[0], subject=topic[1], level=topic[2])
db.session.add(new_topic)
db.session.commit()
return app
def create_database(app):
if not path.exists("CIE Website/" + DB_NAME):
db.create_all(app=app)
To clarify, this "create_app" function is located in an init file in my directory and is called within a separate main python script.
from src import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
This code runs just fine and I'm able to open my website without any errors, but the problem is that the default values I wanted to be initialized don't actually get initialized. My "Topic" table just remains empty.
What I've Tried
So what I assume is going wrong is that the "insert_topics" function is not getting called for whatever reason. To try and fix this I've attempted to simply relocate said function, such as to before the "create_database" call or within my main script after calling the "create_app" function, but all of that just results in the same error (There's even more to this error message, but it's quite long and I'm not sure how important the other information is, so I'm only including this ending statement for now).
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.
Now, all of this stuff is still very much new to me so what I assume to be going wrong may be completely off the mark. It's also possible that I'm overlooking some glaring mistake that's causing all of this. For example, there could be something wrong with the "insert_topics" function itself. Regardless, I hope that one of you will be able to help me figure this out.
P.S.
I apologize in advance for any mistakes I may have made in writing this quesiton. It's my first time doing anything like this.
Alt: How to use a variable and loop it in Flask app route such that it handles multiple webpages which have similar permalinks (i'm not sure what that is though).
This is a snippet of a simple example to demostrate what I mean:
#app.route('/say-hii-1')
def say_hii_1():
return """<h1>Hello 1!</h1>"""
#app.route('/say-hii-2')
def say_hii_2():
return """<h1>Hello 2!</h1>"""
#app.route('/say-hii-3')
def say_hii_3():
return """<h1>Hello 3!</h1>"""
You see, only the number changes in all routes, and the return values also have a pattern. My project is much more complex and has 10-20 such routes.Is there a way, in which I can reduce all of them to just one route?
Some information that you might need:
OS: Ubuntu 19.10
Python version: 3.7.5
What you're looking for is flask route parameters/dynamic routes/variable rules
Route parameters allow you to match your application's route to a pattern, by inserting variables with carats <>. If the url matches the pattern, it'll pass the variable into the function your route is linked to.
From there, you can do whatever sort of dyanmic behaviour you want, as per usual python.
As an example, you could implement what you're asking for in your example as follows:
#app.route('/say-hii-<int:hi_number>')
def say_hii(hi_number):
return "<h1>Hello " + str(hi_number) + "</h1>"
For more information, you can have a look at the flask quickstart:
https://flask.palletsprojects.com/en/1.1.x/quickstart/#routing
This is a fairly common use case, so be sure to look through the flask quickstart and guides next time!
it seems that this problem only arises when i am using flask application factory method
here is the link to repl, and
here is the link to post i made asking fro help (Kindly read the comment section)
I have commented the app.run() part so that it won't start server
#!main.py l:3
#if __name__ == '__main__':
# app.run(host='0.0.0.0')
After running the repl once on the console side i typed
from app.main.models import *
with app.app_context():
db.create_all()
now in theory these line of code should create database with table defined init such that if i do Food.query.all it should return (in theory) an empty list => [] but it returns an error RuntimeError: No application found.
note : Kindly fork the repl you don't need an account for that just click on the fork button beside run because it might show wired when many people run it together
It seems that you've not commit the session & it's not the best practice to import function by *. You should specify specicfic module or Maybe you haven't insert any values in db so you are getting an empty list. I'm not sure about this.But your solution might be in between.
I am trying to create redirects using web2py from effectively the default index page (or just the route of the domain/package).
Some keywords (such as 'about', stored in a list) wouldn't redirect. However, all not in that list would redirect.
The desired behaviour is:
https://startbean.com/about -> No redirect
https://startbean.com/myc -> https://startbean.com/company/myc
The default page that is shown at startbean.com is from the package 'default' and is called 'index'. If the redirect was as in the below, it would be easy:
https://startbean.com/default/about -> No redirect
https://startbean.com/default/index/myc -> https://startbean.com/default/company/myc
because the myc is a URL argument. But when it is from the root, Web2Py tries to open a package called 'myc' and then finds no page (index or controller function) so errors.
What is the best way of handling this? I was trying with routes.py, but couldn't figure out a way to do this (am pretty sure it is not supported). I thought about a redirect for the token after / to a page called /default/redirect/<token> which would then decide about the redirect, but there's no way to stop the infinite loop. Another possible solution was a tweak to the nginx config so redirect when there is one token after the /, but again I think this causes a problem with the about.
Maybe there is a catch-all function for controllers that I haven't found? I've gone through the web2py book and found nothing - any ideas very welcome!
Thanks,
Sam
You can use the parameter-based rewrite system. In routes.py include:
routers = dict(
BASE=dict(
default_application='yourapp',
default_controller='default',
default_function='company',
functions=['index', 'company', 'user', 'download', 'call']
),
)
Note, functions should be a list of all functions in the default.py controller.
If you go to /some_token, it will route to /yourapp/default/company/some_token, unless some_token is "yourapp", "default", "company", or any of the functions in the functions list (in which case, it will assume you are actually requesting the "yourapp" app, the "default" controller, or the particular function from the controller).
Note, if you simply go to the root URL (i.e., http://yourdomain.com/), it will route to /yourapp/default/company/, with no URL arg, so you should be prepared for that case.
So I found the solution (sorry for the delay in posting):
In the routes.py at the route of web2py directory, I added a rule in routes_in, so that this was in the my file:
routes_in = (
('/(?!about)$token', '/company/$token'),
)
to manage the default app (removing the application name and the default package name from the URL), I did this (not necessary for the redirects to work):
routers = dict(
BASE = dict(default_application='startbean'),
)
And it all worked :)
I'm using cherrypy with Mako as a template engine.
I want Mako to lookup different directories based on what app is being requested.
I.e.
I have three 'apps': Site, Admin and Install.
They all have their own template folder, structure looking something like:
/template
/template/site
/template/admin
/template/install
/template/system
/system contains some system wide templates, like 404 pages, etc.
I'm using Twiseless as a reference whilst trying to get to grips with cherrypy / mako, but I'm stuck with how to do this.
Read on for a brief overview of how I've tried to do this, but a warning: I think I'm going about this completely the wrong way! :) So, if you have any ideas/pointers, it might be a good idea to save yourself the trouble of reading any further than this.
In my main file, server.py, I do something like:
from libs.plugins.template import MakoTemplatePlugin
engine = cherrypy.engine
makoTemplate = MakoTemplatePlugin(engine, self.base_dir)
setTemplateDirs(makoTemplate, self.template_path)
MakoTemplatePlugin is a slightly modified version of the plugin by the same name found in Twiseless, linked above.
What this code does is set the TemplateLookup to use the default template directories from my global config file. i.e.
/template
/template/system
Then, each time an app is loaded, I call a function (setTemplateDirs) to update the directories where Mako searches.
I thought this would work, but it doesn't. Initially I made the error of creating a new instance of MakoTemplatePlugin for each app. This just resulted in them all being called on each page load, starting with the first one instantiated, containing just the basic, non-app specific directories.
As this was called first, it was triggering a 404 error, as it was searching in the wrong folders.
I instead made sure to pass a reference to the MakeTemplatePlugin to all of my apps. I thought if I ran setTemplateDirs each time each app is called, this would solve the problem... but it doesn't.
I don't know where to put the function so it will run every time a page is requested...
e.g.
# /apps/site/app.py
import somemodule.setTemplateDirs
class Site(object, params):
def __init__(self):
self.params = params
self.makoTemplate = params['makoTemplate']
self.base_path = params['base_path']
setTemplateDirs(self.makoTemplate, self.base_path, '', '/')
#cherrypy.expose
#cherrypy.tools.render(template='index.html')
def index(self):
pass
This obviously just works when the application is first loaded... I tried moving the update function call into a seperate method update and tried calling that for each page, e.g:
#cherrypy.exposed
#cherrypy.tools.render(template='index.html')
#update
def index(self):
pass
But this just gives me config related errors.
Rather than to continue to mess about with this, there must be an easier way.
How would you do it?
Thanks a lot,
Tom
I got this working. Thanks to stephan for providing the link to the mako tool example: http://tools.cherrypy.org/wiki/Mako.
I just modified that slightly to get it working.
If anyone's wondering, the basis of it is that you define tools.mako.directories in your global config, you can then override that in individual app config files.
e.g.
server.conf
...
tools.mako.directories: ['', 'system']
...
site.conf
...
tools.mako.directories: ['site', 'system']
...
I did some extra work to translate the relative URIs to absolute paths, but the crux of it is explained above.