When i try to use on "/register" POST-body-raw {"name" : "mike", "password" : "demo"} in postman i get this bug, pls help to correct:
line 62, in signup_user
hashed_password = generate_password_hash(data['password'], method='sha256') TypeError: 'NoneType' object is not subscriptable
from flask import Flask, request, jsonify, make_response
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
import uuid
import jwt
import datetime
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Th1s1ss3cr3t'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///library.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
class Users(db.Model):
id = db.Column(db.Integer, primary_key=True)
public_id = db.Column(db.Integer)
name = db.Column(db.String(50))
password = db.Column(db.String(50))
admin = db.Column(db.Boolean)
class Authors(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True, nullable=False)
book = db.Column(db.String(20), unique=True, nullable=False)
country = db.Column(db.String(50), nullable=False)
booker_prize = db.Column(db.Boolean)
user_id = db.Column(db.Integer)
def token_required(f):
#wraps(f)
def decorator(*args, **kwargs):
token = None
if 'x-access-tokens' in request.headers:
token = request.headers['x-access-tokens']
if not token:
return jsonify({'message': 'a valid token is missing'})
try:
data = jwt.decode(token, app.config[SECRET_KEY])
current_user = Users.query.filter_by(public_id=data['public_id']).first()
except:
return jsonify({'message': 'token is invalid'})
return f(current_user, *args, **kwargs)
return decorator
#app.route('/register', methods=['GET', 'POST'])
def signup_user():
data = request.get_json()
hashed_password = generate_password_hash(data['password'], method='sha256')
new_user = Users(public_id=str(uuid.uuid4()), name=data['name'], password=hashed_password, admin=False)
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'registered successfully'})
Most likely your request is missing content-type header.
Content-Type:application/json
In Postman you can set it in Headers tab. Another option is to select "raw" and "JSON (application/json)" in Body tab just above the text area.
Related
I'm trying to write a web app with user roles and I keep getting this error no matter the changes I make.
Could you please help me find what's wrong?
Thank you in advance!!
This is my models.py file:
from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey
from flask_login import UserMixin
from sqlalchemy.orm import relationship, backref
import db
class Rol(db.Base):
__tablename__ = 'Roles'
id_rol = Column(Integer, primary_key=True)
nombre_rol = Column(String, nullable=False)
user_rol = relationship("User rol", back_populates="rol", uselist =False)
def __init__(self, nombre_rol):
self.nombre_rol = nombre_rol
class User(UserMixin, db.Base):
__tablename__ = 'Users'
user_id = Column(Integer, primary_key=True)
username = Column(String, unique=True, nullable=False)
password = Column(String, unique=True, nullable=False)
is_active = Column(Boolean, default=False)
user_rol = relationship("User rol", back_populates="user", uselist =False)
def __init__(self,username,password,is_active):
self.username = username
self.password = password
self.is_active = is_active
def get_id(self):
return self.id
def is_active(self):
return self.is_active
def activate_user(self):
self.is_active = True
def get_username(self):
return self.username
def get_rol(self):
return self.rol
class Roles_users(db.Base):
__tablename__ = 'User Roles'
user_id = Column(Integer, ForeignKey("Users.user_id"))
id_rol = Column(Integer, ForeignKey("Roles.id_rol"))
user = relationship("User", back_populates="user roles")
rol = relationship("Rol", back_populates="user roles")
Below is the code for registration and login form :
from flask_wtf import Flaskform
from wtforms import StringField,PasswordField,SubmitField,BooleanField
from wtforms.validators import DataRequired,Length,EqualTo
class RegistrationForm(Flaskform):
username = StringField('Username',validators=[DataRequired(),Length(min=2,max=20)])
password = PasswordField('Password',validators=[DataRequired()])
confirm_password = PasswordField(' Confirm Password',validators=[DataRequired(),EqualTo('password')])
submit = SubmitField('Sign Up')
class LoginForm(Flaskform):
username = StringField('Username',validators=[DataRequired(),Length(min=2,max=20)])
password = PasswordField('Password',validators=[DataRequired()])
remember = BooleanField("Remember Me")
submit = SubmitField('LOGIN')
the main file is app.py:
from flask import Flask,render_template,request
from flask_sqlalchemy import SQLAlchemy
from login import RegistrationForm,LoginForm
#media for the project
import os
prerna = os.path.join('static','pic.png')
prerna2 = os.path.join('static','Untitled.png')
prerna3 = os.path.join('static','wardrobe.png')
video = os.path.join('static','DigitalWardrobe.mp4')
prerna4 = os.path.join('static','BUUTON.png')
prerna5 = os.path.join('static','start.png')
prerna6=os.path.join('static','home.jpeg')
#create flask app
app = Flask(__name__)
#Database connenction
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///loginForm.db'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['SECRET_KEY'] = 'f79e06501f31fae1c771ee83cc8c3868'
#initialize the database
db = SQLAlchemy(app)
'''class is the table created in the database'''
class loginForm(db.Model):
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(100), unique=True, nullable=False)
password = db.Column(db.String(8), unique=True, nullable=False)
def __repr__(self):
return '<Name %r>' % self.id
with app.app_context():
db.create_all()
#path for the pages
#app.route('/')
def index():
return render_template("index.html",img = prerna2,img1 = prerna,img2 = prerna3,vid=video)
#app.route('/home')
def home() :
return render_template("home.html",title='home',button=prerna4,home=prerna6)
#app.route('/register')
def register():
form = RegistrationForm()
return render_template(register.html,title='Register',form=form)
#app.route('/login')
def login():
form = loginForm()
return render_template(login.html,title='login',form=form)
# #app.route("/login",methods=["GET","POST"])
# def login():
# return render_template("login.html")
#app.route("/createyourcloset")
def createyourcloset():
return render_template("createyourcloset.html",start=prerna5)
#app.route("/opennewcloset")
def opennewcloset():
return render_template("opennewcloset.html")
if __name__=="__main__":
app.run(debug=True)
error :
Traceback (most recent call last):
File "c:\Users\lenovo\OneDrive\Desktop\digifit\login.py", line 1, in
from flask_wtf import Flaskform
ImportError: cannot import name 'Flaskform' from 'flask_wtf' (C:\Users\lenovo\OneDrive\Desktop\digifit\env\Lib\site-packages\flask_wtf_init_.py)
Simple Typo Error: The Class is called FlaskForm not Flaskform
from flask_wtf import FlaskForm
I'm trying to get a server for an app working, but I'm getting an error upon login:
[!] Object '<User at 0x7f12bc185a90>' is already attached to session '2' (this is '3')
It seems the session I'm adding is already on the database. This is the snippet of code that is causing the problem:
#app.route('/login', methods=['POST'])
def login():
u = User.query.filter(User.username == request.form["username"]).first()
if not u or u.password != request.form["password"]:
return error("E1")
s = Session.get_by_user(u)
if s is not None:
db_session.delete(s)
db_session.commit()
print db_session.execute("SELECT * FROM sessions").fetchall()
s = Session(u)
db_session.add(s)
db_session.commit()
return jsonify(s.values)
As you can see, I'm printing the content from the sessions table before trying to add anything, and it is empty! ([])
What else could be causing this?
Here is the 'Session' implementation:
class Session(Base):
__tablename__ = "sessions"
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'), unique=True)
user = relationship(User)
key = Column(String(50), unique=True)
created = Column(DateTime)
def __init__(self, user=None):
self.user = user
self.key = base64.encodestring(os.urandom(24)).strip()
self.created = datetime.now()
def __repr__(self):
return '<Session %r>' % (self.key)
#property
def values(self):
return {"username" : self.user.username,
"key" : self.key,
"created" : str(self.created),
}
#classmethod
def get_by_key(cls, key):
s = cls.query.filter(cls.key == key).first()
#print datetime.now() - s.created
if s and datetime.now() - s.created > settings.SESSION_LIFETIME:
s = None
return s
#classmethod
def get_by_user(cls, user):
s = cls.query.filter(cls.user == user).first()
if s and datetime.now() - s.created > settings.SESSION_LIFETIME:
s.query.delete()
db_session.commit()
s = None
return s
As #marcinkuzminski mentioned, you can't add an object that is already attached to another session. Just pulling in the original session from the object with object_session() is risky, though, if you aren't sure that session originated in the same thread context you're currently operating in. A thread-safe method is to use merge():
local_object = db_session.merge(original_object)
db_session.add(local_object)
db_session.commit()
Object you're trying to modify is already attached to another session.
Maybe you have wrong imports, and db_session is a new instance.
A good workaround to this is to extract the current bound session and use it:
Instead of:
db_session.add(s)
Do:
current_db_sessions = db_session.object_session(s)
current_db_sessions.add(s)
This db session issue will arise if you are having server.py and model.py importing each other
server.py
from flask import Flask
import os
import models as appmod #################### importing models here in server.py<----------
app = Flask(__name__) # L1
app.config.from_object(os.environ['APP_SETTINGS']) # L2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # L3
database = SQLAlchemy(app) # L4
db = database # L5
#app.route('/item_delete/<id>', methods=['DELETE'])
def remove_method(id = None):
data_rec = appmod.Employee.query.get(id)
db.session.delete(data_rec)
db.session.commit()
return "DELETE"
if __name__ == '__main__':
app.run(port=5000, host='0.0.0.0',debug=True,threaded=True)
models.py
from server import db #################### importing server in models.py here <------------
from sqlalchemy.dialects.mysql import JSON
class Employee(db.Model):
__tablename__ = 'employe_flask'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
datetime = db.Column(db.DateTime)
designation = db.Column(db.String(128))
def __init__(self, name, datetime, designation):
self.name = name
self.datetime = datetime
self.designation = designation
#staticmethod
def delete_rec(data_rec):
db.session.delete(data_rec)#.delete
db.session.commit()
def __repr__(self):
record = {"name":self.name,"date":self.datetime.ctime(),"designation":self.designation}.__str__()
return record
Remove the line L1 to L5 from server.py and place it in common file like settings.py
and import 'app' and 'db' to server.py and import db in models.py
like this files below
server.py
from flask import Flask
import os
import models as appmod
from settings import app, db
#app.route('/item_delete/<id>', methods=['DELETE'])
def remove_method(id = None):
data_rec = appmod.Employee.query.get(id)
db.session.delete(data_rec)
db.session.commit()
return "DELETE"
if __name__ == '__main__':
app.run(port=5000, host='0.0.0.0',debug=True,threaded=True)
settings.py
import os
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__) # L1
app.config.from_object(os.environ['APP_SETTINGS']) # L2
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # L3
database = SQLAlchemy(app) # L4
db = database # L5
models.py
from settings import db
from sqlalchemy.dialects.mysql import JSON
class Employee(db.Model):
__tablename__ = 'employe_flask'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
datetime = db.Column(db.DateTime)
designation = db.Column(db.String(128))
def __init__(self, name, datetime, designation):
self.name = name
self.datetime = datetime
self.designation = designation
#staticmethod
def delete_rec(data_rec):
db.session.delete(data_rec)#.delete
db.session.commit()
def __repr__(self):
record = {"name":self.name,"date":self.datetime.ctime(),"designation":self.designation}.__str__()
return record
This error means the record you are handling is attached to 2 different session(db)!
One of the reasons is that you may define your model with one db = SQLAlchemy(app) and add/insert/modify the database with another!
My solution is UNIFORMING THE DB!
try this:
u = db.session.query(User).filter(User.username == request.form["username"]).first()
Instead of this:
u = User.query.filter(User.username == request.form["username"]).first()
I had this problem too.
I created a test_file.py and added this code:
from app import app
from models import Tovar
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
tovardel = Tovar.query.filter(Tovar.region == 1 and Tovar.price == 12).first()
db.session.delete(tovardel)
tovar = Tovar.query.filter(Tovar.region == 1 and Tovar.price == 12).first()
print(tovar.description)
and when I ran the code I got this error:
Object '<Tovar at 0x7f09cbf74208>' is already attached to session '1' (this is '2')
PROBLEM SOLVING:
If you have db = SQLAlchemy(app) in, for example, text_file.py, and in app.py, you get this problem all time. You should del db = SQLAlchemy(app), and import db from app from app import db
I faced the same issue. I was defining models in a separate file and I had to call SQLAlchemy twice. That's why there were two different sessions were running.
I solved this by doing following:
In case you are trying to remove an object from db:
Just create the removeObject function inside the model
Here is code for my models:
class IllustratorAsset(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
uploader = db.Column(db.Integer, db.ForeignKey('user.id'))
project = db.Column(db.Integer, db.ForeignKey('project.id'))
fragments = db.relationship('AssetFragment', backref='ai', lazy='dynamic')
file_hash = db.Column(db.String(128), unique=True)
file_name = db.Column(db.String(128))
def __repr__(self):
return '<Picture {}>'.format(self.id)
tags_association = db.Table(
'tags_association',
db.Column('fragment_id', db.Integer(), db.ForeignKey('asset_fragment.id'),index=True),
db.Column('tag_id', db.Integer(), db.ForeignKey('tag.id'),index=True),
PrimaryKeyConstraint('fragment_id', 'tag_id')
)
class AssetFragment(db.Model):
id = db.Column(db.Integer, primary_key=True)
asset = db.Column(db.Integer, db.ForeignKey('illustrator_asset.id'))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
uploader = db.Column(db.Integer, db.ForeignKey('user.id'))
tags = db.relationship('Tag', secondary=tags_association, backref='fragments', lazy='dynamic')
file_name = db.Column(db.String(128))
file_hash = db.Column(db.String(128))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
tag = db.Column(db.String(64), index=True, unique=True)
def __repr__(self):
return '<Tag {}>'.format(self.tag)
The idea is illustrations storage, there is Asset (Adobe Illustrator file), it has Fragments (renders of its different fragments), the fragment has some Tags for quick search which should be working through many-to-many relationship tags_association.
Currently, I'm stuck at trying to check if an association already exists, I'm sure there is some simple way to do it, but I'm missing some point. I came up with the code below, and I still get the exception of constraints.
for tag in new_tags: #list of tags from form
t = Tag.query.filter_by(tag=tag).first()
if (t is not None) and not(t in fragment.tags):
fragment.tags.append(t)
else:
new_tag = Tag(tag=tag)
if not(new_tag in fragment.tags):
fragment.tags.append(new_tag)
DB is Postgres
Well answer came shortly after I've tried to do it in flask shell. Shell output
I've realized, that it seems to be something wrong with the comparator, simple override makes it work:
def __eq__(self, __o: object) -> bool:
return self.tag == __o.tag
Also needed to change checking by a bit:
for tag in new_tags:
t = Tag.query.filter_by(tag=tag).first()
if t is None:
new_tag = Tag(tag=tag)
print(new_tag)
if not(new_tag in fragment.tags):
fragment.tags.append(new_tag)
else:
print(t)
if not(t in fragment.tags):
fragment.tags.append(t)
I am trying to get a nested serialized output, but all I get is the 'many' side of the many-to-one's table's primary key.
Expected output:
[{'part_numbers':
{'part_number': '23103048', 'description': 'blue product'},
'machines': 2,
'percent_complete': 5.0,
'serial_number': '001',
'timestamp_created': 2020-03-12T15:4:23.135098},
{'part_numbers':
{'part_number': '44444009', 'description': 'red product'},
'machines': 1,
'percent_complete': 60.0,
'serial_number': '002',
'timestamp_created': '2020-03-12T15:44:23.135098'}]
Actual output:
[{'id': 3,
'machines': 2,
'percent_complete': 5.0,
'serial_number': '001',
'timestamp_created': 2020-03-12T15:4:23.135098},
{'id': 1,
'machines': 1,
'percent_complete': 60.0,
'serial_number': '0002',
'timestamp_created': '2020-03-12T15:44:23.135098'}]
These are my files. I have tried adding part_numbers = ma.Nested(PartNumbers) to the Machine schema inside models.py, but it didn't change the result!
my_app
|--- my_app
|--- \__init\__.py
|--- models.py
|--- views.py
models.py
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
db = SQLAlchemy()
ma = Marshmallow()
### Models ###
class Machine(db.Model):
id = db.Column(db.Integer, primary_key=True)
serial_number = db.Column(db.Text, unique=True)
percent_complete = db.Column(db.Float)
part_number_id = db.Column(db.Integer, db.ForeignKey('PartNumbers.id'))
timestamp_created = db.Column(db.DateTime, default=datetime.utcnow)
class PartNumbers(db.Model):
__tablename__ = 'PartNumbers'
id = db.Column(db.Integer, primary_key=True)
part_number = db.Column(db.Text, unique=True)
description = db.Column(db.Text)
machines = db.relationship('Machines', backref='machines', lazy='dynamic')
### Schemas ###
class PartNumbersSchema(SQLAlchemyAutoSchema):
class Meta:
model = PartNumbers
include_fk = True
class MachineSchema(SQLAlchemyAutoSchema):
class Meta:
model = Machines
include_relationships = True
__init__.py
from flask import Flask
from .models import db, ma
from .views import my_app
app = Flask(__name__)
db.init_app(app)
ma.init_app(app)
app.register_blueprint(my_app)
views.py
from flask import Blueprint
from .models import db, Machines, MachineSchema, PartNumbers
my_app = Blueprint("my_app", __name__)
machines_schema = MachineSchema(many=True)
#my_app.route('/')
def home()
machines = db.session.query(Machines).all()
return machines_schema.dump(machines)
Define part_number in the Machine class:
class Machine(db.Model):
id = db.Column(db.Integer, primary_key=True)
serial_number = db.Column(db.Text, unique=True)
percent_complete = db.Column(db.Float)
part_number_id = db.Column(db.Integer, db.ForeignKey('PartNumbers.id'))
timestamp_created = db.Column(db.DateTime, default=datetime.utcnow)
part_numbers = db.relationship('PartNumbers')
You have to define part_numbers in the MachineSchema explicitly:
from marshmallow_sqlalchemy import fields
class MachineSchema(SQLAlchemyAutoSchema):
class Meta:
model = Machines
part_numbers = fields.Nested(PartNumbersSchema)
I assumed part_numbers is a single object (1:1 relationship). Otherwise, you have to add many=True to part_numbers.
More details: https://marshmallow.readthedocs.io/en/stable/nesting.html
[edited to incorporate correction in comment]