I'm trying to set up a flask server which adds data/users to a mongoDB database.
I set up the DB (using mongo shell) like so:
>use dbname
switched to dbname
>db.users.save( {username:"user", password:"pass"} )
WriteResult({ "nInserted" : 1 })
And confirm the data is written with db.users.find().
I added a mongo user like so:
>use admin
switched to db admin
>var w = { user:"user", roles:["readWriteAnyDatabase"], pwd:"password"}
>db.createUser(w)
My config.py looks like:
...
MONGO_URI = 'mongodb://user:password#localhost:27017/dbname'
and my python looks like this:
from flask import render_template, flash, redirect, Flask
from app import app
from flask_pymongo import PyMongo
from .forms import LoginForm
appp = Flask(__name__)
mongo = PyMongo(appp)
#app.route('/login', methods=['GET', 'POST'])
def login:
form = LoginForm()
if form.validate_on_submit():
user = {"username": form.username.data,
"password": form.password.data}
post_id = mongo.db.users.insert_one(user)
flash('Login req: u=%s, p=%s' % (form.username.data, str(form.remember_me.data)))
return redirect('/index')
I thought all was well but I got this when I tried it out:
It appears to say something about the config_prefix? The docs say config_prefix is set to 'MONGO' by default and in my config the prefix is mongo. I must be missing something SOS
Kostas was correct.
I changed:
appp = Flask(__name__)
mongo = PyMongo(appp)
to simply
mongo = PyMongo(app)
You have a typo in
#app.route('/login', methods=['GET', 'POST'])
PyMongo uses current_app variable from flask which refers to the application instance handling the request. In this case app handles the request but appp has the configuration. So this line should become
#appp.route('/login', methods=['GET', 'POST'])
Related
So what I did is that I tried to run my flask app but suddenly I got a error which is
TypeError: storage must be a werkzeug.FileStorage
This is the code that I use...
init.py
# IMPORT
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
from blogapp.config import Config
# INIT
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
migrate = Migrate()
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
photos = UploadSet('photos', IMAGES)
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
configure_uploads(app, photos)
patch_request_class(app)
from blogapp.users.routes import users
from blogapp.posts.routes import posts
from blogapp.main.routes import main
from blogapp.errors.handlers import errors
app.register_blueprint(users)
app.register_blueprint(posts)
app.register_blueprint(main)
app.register_blueprint(errors)
return app
config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI')
UPLOADED_PHOTOS_DEST = os.path.join(basedir, 'uploads')
I have a uploads folder in my parent directory
routes.py
from flask import (render_template, url_for, flash,
redirect, request, abort, Blueprint)
from flask_login import current_user, login_required
from blogapp import db, photos
from blogapp.models import Post
from blogapp.posts.forms import PostForm
posts = Blueprint('posts', __name__)
#posts.route("/post/new", methods=['GET', 'POST'])
#login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
filename = photos.save(form.photo.data)
file_url = photos.url(filename)
else:
file_url = None
if form.validate_on_submit():
post = Post(title=form.title.data, content=form.content.data, image=form.photo.data, author=current_user)
db.session.add(post)
db.session.commit()
flash('Your post has been created!', 'success')
return redirect(url_for('main.home'))
return render_template('create_post.html', title='New Post',
form=form, file_url=file_url, legend="Post")
Can someone help me?
I'm a bit confuse with how I got the error..
Did I do something wrong?
There isn't any thing I could find out there, so for me this is very confusing..
Could it be something wrong with the application factory while using flask upload?
Traceback
When I have a look at your routes.py, I see some possible problems.
new_post does accept both get and post requests, but does not handle them differently.
e.g. usually when there is a get request, you want to just render the empty form, but when there is a post request, you want to e.g. save the file.
You have two if form.validate_on_submit statements. You can simplify them when you move the else to the bottom, just above the return statement. Actually, you do not need an else path as, when the if path is valid, you leave the function with the return redirect already.
About your problem.
The error message clearly says, that form.photo.data is no uploaded file.
Please fix the above suggestions and try it again.
Also make sure you do not send an empty form. Btw - you did not show your form template. Maybe there is no data field?
If you followed all suggestions, but without success, please set a breakpoint just after e.g. form = PostForm() and carefully step through your program and especially inspect what value form.photo.data shows.
All you have to do is in your HTML file, set the FORM "enctype = multipart/form-data"
i want to create a simple web application who use a connection to a vCenter Server, and i want to pass the variable connection between pages, instead of recreate this connection on every page.
This is the code:
#!/bin/env python
from flask import Flask, request, redirect, render_template, session
from flask import Flask, request, redirect, render_template, session
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired
from modulo import MyForm
from pyVim import connect
from pyVim.connect import SmartConnectNoSSL, Disconnect
from pyVmomi import vim
app = Flask(__name__)
#app.route('/')
def index():
return redirect('/submit')
#app.route('/submit', methods=('GET', 'POST')) #ENTER USERNAME AND PASSWORD, SAVE ON /SUCCESS
def submit():
form = MyForm()
if form.validate_on_submit():
return redirect('/success')
return render_template('submit.html', form=form)
#app.route('/success', methods=('GET', 'POST')) #ESTABILISH CONNECTION USING USERNAME AND PASSWORD CREDENTIALS
def success():
form = MyForm()
username = form.username.data
password = form.password.data
c = SmartConnectNoSSL(host='10.116.xxx.xxx', user=username, pwd=password)
datacenter = c.content.rootFolder.childEntity[0]
clusters = datacenter.hostFolder
cluster = clusters.childEntity[0]
esxi = cluster.host
return render_template('success.html', esxi=esxi)
#app.route('/hosts', methods=('GET', 'POST'))
def hosts():
macchine = request.form.getlist('host')
for i in esxi:
for x in macchine:
if i.name == x:
do something..
return FINISH
if __name__ == '__main__':
app.secret_key='Secret'
app.debug = True
app.run(host = '0.0.0.0', port = 3000)
i want to reuse the c variable (the connection to the server) in other pages, and the object who derived from this variable for example esxi (list of object).
if i run the code, flask say: global name 'esxi' is not defined
How can i do this?
In flask you can store variables on your app object and reuse them later. Example:
app = Flask(__name__)
app.c = SmartConnectNoSSL(host='10.116.xxx.xxx', user=username, pwd=password)
# You can now reuse the connection like so
datacenter = app.c.content.rootFolder.childEntity[0]
I just started learning to develop on Flask (through the 'fullstack' course on Udacity).
But I was wondering, is it normal that when I restart/close my server all the data I had changed from my "website" while the server was previously up, is gone? (I don't know if I clearly explained the problem).
If yes, how to make it so that the data is saved in the database even if I close the server?
this is an example of what the code looks like:
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from database_setup import Base, Restaurant, MenuItem
app = Flask(__name__)
engine = create_engine('sqlite:///restaurantmenu.db')
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
(...)
#app.route('/restaurants/<int:restaurant_id>/new', methods=['GET', 'POST'])
def newMenuItem(restaurant_id):
if request.method == 'POST':
newItem = MenuItem(name=request.form['name'], description=request.form['description'], price=request.form['price'], course=request.form['course'], restaurant_id=restaurant_id)
session.add(newItem)
session.commit
flash("new menu item created !")
return redirect(url_for('restaurantMenu', restaurant_id=restaurant_id))
else:
return render_template('newmenuitem.html', restaurant_id=restaurant_id)
(...)
if __name__ == '__main__':
app.secret_key = 'super_secret_key'
app.debug = True
app.run(host = '0.0.0.0', port=5000)
Just copying my comment into an answer.
If this is working code you posted try using session.commit() with he brackets. Right now you never call commit and nothing will be stored in the database.
I am building a simple web-app which uses existing MySQL DB. It is my first time using Flask and I have been struggling to understand what I am doing wrong for the past couple of hours.
My simple project structure:
/root
/app
__init__.py
db.py
forms.py
views.py
/templates
base.html
index.html
login.html
config.py
run.py
I am trying to query my MySQL DB and fill the template with the result from the query.
My db.py:
from app import app
from flaskext.mysql import MySQL
class DB(object):
mysql = MySQL()
def __init__(self):
app.config['MYSQL_DATABASE_USER'] = 'loguser'
app.config['MYSQL_DATABASE_PASSWORD'] = 'asdzxc'
app.config['MYSQL_DATABASE_DB'] = 'log'
app.config['MYSQL_DATABASE_HOST'] = '127.0.0.1'
app.config['MYSQL_DATABASE_PORT'] = 33006
self.mysql.init_app(app)
def query_db(self):
cursor = self.mysql.connect().cursor()
cursor.execute("SELECT name from users limit 1")
data = cursor.fetchone()
if data is None:
return "No results from query"
else:
return data
And in my views.py I have the following:
from flask import render_template, flash, redirect
from app import app
from .forms import LoginForm
from .db import DB
#app.route('/')
#app.route('/index')
def index():
db = DB()
user = db.query_db()
print(user) (it prints it here so the db connection works)
posts = [ # fake array of posts
{
'author': {'nickname': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'nickname': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html",
title='Home',
user=user,
posts=posts)
I get "AssertionError" when I try to assign "user" to the user from the template:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
I believe I am violating a major principle of the framework. What is the correct way to pass the data to the template?
It is better to use Flask-SQLAlchemy and MySQL-python 1.2 , Successful code and documentation is available on the link below.
http://techarena51.com/index.php/flask-sqlalchemy-tutorial/
From my experience I found that MySQl support is not that good for python 3 atleast, it is better to use PostgreSQL, but that's just my personal opinion.
It's very late to give answer, but it may help someone.
You've to connect to MySQL before adding any route source to an API.
It should be in the order of
# 1. MySQL setup should be done at first
app = Flask(__name__)
api = Api(app)
mysql = MySQL()
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'DataBase'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
# 2. Create API resource after that
api.add_resource(CreateUser, '/CreateUser')
I have multiple blueprints that needs to be integrated into a single app. I'm using flask-login to handle logins. However I'm confused on how to handle the LoginManager() and the .user_loader for my blueprints.
This is my current file structure.
system/
run.py
config.py
app/
__init__.py
models.py
views/
blueprint1.py
blueprint2.py
static/
templates/
<templates>
What's the correct way to implement them? Do I just call them at the __init__.py and import the login manager variable at the blueprints? or Do I need to call them individually in the blueprints?
Hopefully I'm able to portray the question clearly. Thank you for reading and answering
You must understand that for one application you must use one login manager no matter how many blueprints you use (of course there can be specific exceptions for example when blueprints are independent, but in this case you probably can't use flask-login). Because:
You have 1 entry point
If user is not logged in, he will be redirected to login/registration page
You have 1 user loader
How login manager works:
It registers current_user in request context
before_request reads your session, gets user id, loads the user with user_loader and set it to current_user or AnonymousUser
When you visit the private page, login_required checks current_user.is_authenticated() else redirects to login page
On login, it adds user id to the session
So you must initialize only one login manager instance for flask application and then use login_required and current_user in all your blueprints.
This is how I have handled it:
This is where I am initialising everything:
import logging
import logging.config
import flask
import flask.globals as flask_global
import flask_login
from config import flask as flask_config
from rest.api import dashboard
from rest.api.util import login_decorator
logger = logging.getLogger(__name__)
# app
flask_app = flask.Flask(__name__)
flask_app.config.from_object(flask_config)
# login manager needs be set before blueprint registration
login_manager = flask_login.LoginManager()
login_manager.init_app(flask_app)
flask_app.register_blueprint(dashboard.blueprint)
# setting blueprint specific login view
# login_manager.login_view = "login"
#login_manager.user_loader
def load_user(user_id):
"""
This will be used many times like on using current_user
:param user_id: username
:return: user or none
"""
# http://librelist.com/browser/flask/2012/4/7/current-blueprint/#44814417e8289f5f5bb9683d416ee1ee
blueprint = flask_global.current_app.blueprints[request.blueprint]
if hasattr(blueprint, load_user):
return blueprint.load_user(user_id)
# https://flask-login.readthedocs.org/en/latest/#how-it-works
return None
Here is my blueprint with its own handling of login:
from __future__ import absolute_import
import flask
import flask_login
from flask import Blueprint
from core.models.profile import Agent
from core.utils import thread_local
from rest.api.util import login_decorator
blueprint = Blueprint('human', __name__, url_prefix='/human')
def load_user(user_id):
"""
This will be used many times like on using current_user
:param user_id: username
:return: user or none
"""
agent = None
try:
agent = Agent.objects.get(username=user_id)
except:
# https://flask-login.readthedocs.org/en/latest/#how-it-works
pass
return agent
#blueprint.record_once
def on_load(state):
"""
http://stackoverflow.com/a/20172064/742173
:param state: state
"""
blueprint.load_user = load_user
state.app.login_manager.blueprint_login_views[blueprint.name] = 'human.login'
#blueprint.route('/login', methods=['POST'])
#login_decorator.login_not_required
def login():
username = flask.request.args.get('username')
password = flask.request.args.get('password')
try:
agent = Agent.objects.get(username=username)
except:
return 'Invalid username'
if not agent.check_password(password):
return 'Invalid password'
flask_login.login_user(agent)
return 'Valid login'
#blueprint.route("/logout")
def logout():
flask_login.logout_user()
return 'Logout done'
#blueprint.before_request
def before_request():
agent = flask_login.current_user
# https://flask-login.readthedocs.org/en/latest/#anonymous-users
is_logged_in = agent.get_id() is not None
login_not_required = getattr(flask.current_app.view_functions[flask.request.endpoint], 'login_not_required', False)
is_static_resource_call = flask.request.endpoint.startswith('static/')
if is_static_resource_call or is_logged_in or login_not_required:
if is_logged_in:
thread_local.set_current_brand_id(agent.brand_id)
else:
flask.abort(401)
# if we want to redirect to some page then we can use this. The appropriate login_view should be set
# return flask.current_app.login_manager.unauthorized()
Hope it helps.
In case anyone still faces this challenge due to the documentation not being so clear, here is a solution
In your case, you need to place the login manager declaration in the same file as the flask app instance. This is commonly an __init__.py file with the app = Flask(__name__).
At the top, import LoginManager class
from flask_login import LoginManager
Then tie it to the app instance.
login_manager = LoginManager()
login_manager.init_app(app)
(This was not asked but just incase someone needs it) Lets say you have admins and normal users and you are authenticating from different tables:
#login_manager.user_loader
def load_user(user_id):
x = Users.query.get(str(user_id))
if x == None:
x = Admins.query.get(str(user_id))
return x
Finally after importing blueprints you can define the login views for each in a dictionary
login_manager.blueprint_login_views = {
'admin': '/admin/login',
'site': '/login',
}
Since you tied the login manager to the flask app instance, there is no need of importing it into any blueprint
The documentation is unclear and I will put down what I come up with after spending some time researching.
You only need to define login_manager once in the flask app.py and init_app.
Then at each blueprint, add from flask_login import login_required at top and use the #login_required as usual. Turns out it can be used without stating the login_manager.
Code example (app with single blueprint)
app.py
import flask
from flask import redirect, url_for
import flask_login
from blueprint.secret import secret_bp
from model.user import User
login_manager = flask_login.LoginManager()
app = flask.Flask(__name__)
app.register_blueprint(secret_bp, url_prefix="/secret")
login_manager.init_app(app)
#login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
#app.route('/login', methods=['GET', 'POST'])
def login():
if flask.request.method == "GET":
return "<form action='/login' method='POST'><input type='text' name='user'><button type='submit'>Submit</button></form>"
user = flask.request.form.get('user')
if user == "user":
# Login and validate the user.
# user should be an instance of your `User` class
flask_login.login_user(user)
flask.flash('Logged in successfully.')
return flask.redirect(next or flask.url_for('index'))
return flask.redirect(flask.url_for('login'))
#app.route('/admin')
def admin():
return "Admin page"
#login_manager.unauthorized_handler
def unauthorized():
# do stuff
return redirect(url_for('login'))
secret.py
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
from flask_login import login_required
secret_bp = Blueprint('secret', __name__,
template_folder='templates')
#secret_bp.route('/noneed')
def no_need():
return "You can see this without login."
#secret_bp.route('/needlogin')
#login_required
def show():
return "can't see this if not login"
As expected, /secret/noneed can be access without login and /secret/needlogin will redirect you with the function stated with #unauthorized_handler.