How to store multiple image filepaths in flask sqlachemy? - python

I am trying to build a webpage with a Project class and Project class will have multiple image files.
I can upload and store the image files but can't insert the file paths of images to database. So i can call the image paths from db. I have a sqlite db and i use Flask-SQLAlchemy.
Here is my Project Class. I've messed up a bit.
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
description = db.Column(db.Text, nullable=False)
header_image = db.Column(db.String(30), nullable=False, default='default_project.jpg')
project_images = db.relationship('ImageSet', backref='project', lazy=True, uselist=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Project('{self.title}', {self.date_posted}')"
class ImageSet(db.Model):
id = db.Column(db.Integer, primary_key=True)
imageset = db.Column(db.String(120), nullable=False)
project_id = db.Column(db.Integer, db.ForeignKey('project.id'), nullable=False)
And this is the route and function to add projects
def save_picture(form_picture):
random_hex = secrets.token_hex(8)
_, f_ext = os.path.splitext(form_picture.filename)
picture_fn = random_hex + f_ext
picture_path = os.path.join(app.root_path, 'static/images/project_images', picture_fn)
output_size = (1280, 720)
i = Image.open(form_picture)
i.thumbnail(output_size)
i.save(picture_path)
return picture_fn
#app.route('/add_project', methods=["GET", "POST"])
#login_required
def add_project():
form = AddProjectForm()
imageset = ImageSet()
if form.validate_on_submit():
if form.header_image.data:
header_image = save_picture(form.header_image.data)
if form.project_images.data:
for image in form.project_images.data:
image = save_picture(image)
project = Project(title=form.title.data, description=form.description.data, project_images=, user_id=current_user.id)
db.session.add(project)
db.session.commit()
flash('Project Successfully Added', 'succes')
return render_template('add_project.html', title='Add Project', form=form)
return render_template('add_project.html', title='Add Project', form=form)

Thanks to #JosefKorbel, i've figured out the solution.
For anyone who may need the answer of the problem:
I used one-to-many relationship in classes.
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
description = db.Column(db.Text, nullable=False)
header_image = db.Column(db.String(30), nullable=False, default='default_project.jpg')
project_images = db.relationship('ImageSet', backref='project_images', lazy=True, uselist=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Project('{self.title}', {self.date_posted}')"
class ImageSet(db.Model):
id = db.Column(db.Integer, primary_key=True)
image = db.Column(db.String(120), nullable=False)
project_id = db.Column(db.Integer, db.ForeignKey('project.id'), nullable=False)
Route, image saving functions:
def save_picture(form_picture):
random_hex = secrets.token_hex(8)
_, f_ext = os.path.splitext(form_picture.filename)
picture_fn = random_hex + f_ext
picture_path = os.path.join(app.root_path, 'static/images/project_images', picture_fn)
output_size = (1280, 720)
i = Image.open(form_picture)
i.thumbnail(output_size)
i.save(picture_path)
return picture_fn
#app.route('/add_project', methods=["GET", "POST"])
#login_required
def add_project():
form = AddProjectForm()
if form.validate_on_submit():
if form.header_image.data:
header_image = save_picture(form.header_image.data)
project = Project(title=form.title.data, description=form.description.data, header_image=header_image, user_id=current_user.id)
if form.project_images.data:
for image in form.project_images.data:
image = save_picture(image)
project.project_images.append(ImageSet(image=image))
time.sleep(2)
db.session.add(project)
db.session.commit()
flash('Project Successfully Added', 'succes')
return render_template('add_project.html', title='Add Project', form=form)
return render_template('add_project.html', title='Add Project', form=form)
i used time.sleep(2) before proccessing each image because sqlite is locking the database if i dont wait.

Related

Problems to make relationships between four tables Flask and flask-sqlalchemy

im learning about Flask and flask-sqlalchemy relationships. I have five tables Clientes, Solicitud, Cotizacion, Servicio, Asesor. Im trying to get Service cost for a specific Request (Solicitud) table but i dont get it, why i cant get this value for a specific id Request (Solicitud) in crearcotizacion view. The process is like this: A client is created, then a Service and a Asesor(Advisor) is created. Then in crearsolicitudes view, all clients are listed, click on crear solicitud plus button, and then the create request form appears, the data of the client and request all ok. When i try to create a new quotation (cotizacion) crearcotizacion view, i cant bring the cost of the service value that belongs to that request and service. I try to create a foreing key between request (Solicitud) and Servicio but it doesnt work.
My Model
class Clientes(db.Model):
__tablename__ = "clientes"
id = db.Column(db.Integer, primary_key=True)
nombres = db.Column(db.String(80), nullable=False)
apellidos = db.Column(db.String(80), nullable=False)
correo = db.Column(db.String(120), nullable=False)
empresa = db.Column(db.String(120), nullable=False)
celular = db.Column(db.String(50), nullable=False)
mensaje = db.Column(db.String(500), nullable=False)
checkbox = db.Column(db.Boolean, nullable=False)
cotizaciones = db.relationship('Cotizacion', backref='clientes_cotizan', lazy=True)
solicitudes = db.relationship('Solicitud', backref='sol_client', lazy=True)
servicios = db.relationship('Servicio', backref='clientes_servicios', lazy=True)
def __init__(self, nombres, apellidos, correo, empresa, celular, mensaje, checkbox, sol_client, clientes_servicios):
self.nombres = nombres
self.apellidos = apellidos
self.correo = correo
self.empresa = empresa
self.celular = celular
self.mensaje = mensaje
self.checkbox = checkbox
self.sol_client = sol_client
self.clientes_servicios = clientes_servicios
def __repr__(self):
return '<Clientes %r>' % self.id
class Solicitud(db.Model):
__tablename__ = "solicitud"
id = db.Column(db.Integer, primary_key=True)
servicio_campo = db.Column(db.String(120), nullable=False)
asesore = db.Column(db.String(120), nullable=False)
# LLAVE FORANEA
solicitud_cliente = db.Column(db.Integer, db.ForeignKey("clientes.id"), nullable=True)
solicitudes_cliente = db.relationship('Cotizacion', backref='clientes_solicitan', lazy=True)
solicitudes_servicio = db.relationship('Servicios', backref='solicitud_servicios', lazy=True)
def __init__(self, servicio_campo, asesore, sol_client, clientes_servicios):
self.servicio_campo = servicio_campo
self.asesore = asesore
self.sol_client = sol_client
self.clientes_servicios = clientes_servicios
class Cotizacion(db.Model):
__tablename__ = "cotizacion"
id = db.Column(db.Integer, primary_key=True)
numero_horas = db.Column(db.Integer, nullable=False)
descuento = db.Column(db.Integer, nullable=False)
valor_total = db.Column(db.Integer, nullable=False)
# LLAVE FORANEA
cliente_id = db.Column(db.Integer, db.ForeignKey("clientes.id"), nullable=True)
solicitud_id = db.Column(db.Integer, db.ForeignKey("solicitud.id"), nullable=True)
def __init__(self, numero_horas, descuento, valor_total, clientes_cotizan, clientes_solicitan):
self.numero_horas = numero_horas
self.descuento = descuento
self.valor_total = valor_total
self.clientes_cotizan = clientes_cotizan
self.clientes_solicitan = clientes_solicitan
def __repr__(self):
return '<Cotizacion %r>' % self.id
class Servicio(db.Model):
__tablename__ = "servicio"
id = db.Column(db.Integer, primary_key=True)
nombre_servicio = db.Column(db.String(120), nullable=False)
costo_servicio = db.Column(db.Integer, nullable=False)
# LLAVE FORANEA
cliente_id = db.Column(db.Integer, db.ForeignKey("clientes.id"), nullable=True)
solicitud_id = db.Column(db.Integer, db.ForeignKey("solicitud.id"), nullable=True)
def __init__(self, nombre_servicio, costo_servicio, clientes_servicios, solicitud_servicios):
self.nombre_servicio = nombre_servicio
self.costo_servicio = costo_servicio
self.clientes_servicios = clientes_servicios
self.solicitud_servicios = solicitud_servicios
class Asesor(db.Model):
__tablename__ = "asesor"
id = db.Column(db.Integer, primary_key=True)
primernombre_asesor = db.Column(db.String(120), nullable=False)
apellido_asesor = db.Column(db.String(120), nullable=False)
correo_asesor = db.Column(db.String(150), nullable=False)
def __init__(self, primernombre_asesor, apellido_asesor, correo_asesor, asesor_client):
self.primernombre_asesor = primernombre_asesor
self.apellido_asesor = apellido_asesor
self.correo_asesor = correo_asesor
self.asesor_client = asesor_client
My Views
#app.route('/cotizacion/crear/<int:id>', methods=("GET", "POST"))
#login_required
def crearcotizacion(id):
datos_solicitud = (db.session.query(Solicitud).filter_by(id=id).first())
datos_clientes = datos_solicitud.sol_client
datos_servicio = (db.session.query(Solicitud, Servicio.costo_servicio).join(Servicio).filter_by(id=id).first())
print(datos_servicio)
form = creacion_Cotizacion(request.form)
if current_user.role == True:
if request.method == 'POST':
cotizan = Cotizacion(
numero_horas=form.numero_horas.data,
descuento=form.descuento.data,
clientes_cotizan=datos_clientes,
clientes_solicitan=datos_solicitud,
clientes_servicios=datos_solicitud
)
db.session.add(cotizan)
db.session.commit()
flash('La cotización ha sido creado exitosamente', 'success')
return render_template('crearcotizacion.html', form=form, id=id, datos_solicitud=datos_solicitud, datos_clientes=datos_clientes, datos_servicio=datos_servicio)
else:
abort(401)
return render_template('crearcotizacion.html', nombres=current_user.nombres, correo=current_user.correo, role=current_user.role, id=id, form=form, datos_solicitud=datos_solicitud, datos_clientes=datos_clientes, datos_servicio=datos_servicio)
#app.route('/crearsolicitudes/crear/<int:id>', methods=("GET", "POST"))
#login_required
def crearsolicitud(id):
client = (db.session.query(Clientes).filter_by(id=id).one())
form = form_solicitudes(request.form)
datos_solicitud = (db.session.query(Solicitud).filter_by(id=id).first())
if current_user.role == True:
if request.method == 'POST':
solicitan = Solicitud(
servicio_campo = form.servicio_campo.data,
asesore = form.asesore.data,
sol_client = client,
clientes_servicios=datos_solicitud
)
db.session.add(solicitan)
db.session.commit()
message = f"La solicitud {solicitan.id} ha sido creada exitosamente"
flash(message, 'success')
return redirect(url_for('versolicitudes', client=client, id=id, form=form, nombres=current_user.nombres, correo=current_user.correo, role=current_user.role,))
else:
abort(401)
return render_template('crearsolicitudes.html', nombres=current_user.nombres, correo=current_user.correo, role=current_user.role, id=id, client=client, form=form)
#app.route('/crearcliente', methods=("GET", "POST"))
#login_required
def crearcliente():
clint = db.session.query(Clientes).filter_by(id=id).first()
form = creacion_Cliente(request.form)
client= Clientes(
nombres=form.nombres.data,
apellidos=form.apellidos.data,
correo=form.correo.data,
empresa=form.empresa.data,
celular=form.celular.data,
mensaje = form.mensaje.data,
checkbox = form.checkbox.data,
sol_client = clint,
clientes_servicios = clint)
if current_user.role == True:
if request.method == 'POST':
db.session.add(client)
db.session.commit()
message = f"El cliente {client.nombres} {client.apellidos} ha sido creado exitosamente"
flash(message, 'success')
return redirect(url_for('listarclientes', form=form))
else:
abort(401)
return render_template('crearcliente.html', form=form, nombres=current_user.nombres, correo=current_user.correo, role=current_user.role)
#app.route('/ver-solicitudes')
#login_required
def versolicitudes():
if current_user.role == True:
clientes= db.session.query(Solicitud.id, Solicitud.servicio_campo, Solicitud.asesore, Clientes.nombres, Clientes.apellidos, Clientes.correo, Clientes.empresa, Clientes.mensaje, Clientes.celular).join(Clientes).all()
return render_template('listacotizacion.html', clientes=clientes, nombres=current_user.nombres, correo=current_user.correo)

Using SQLAlchemy, I need to assign users into pools, and a ranking for each pool they're in

Here is the relevant code.
I'm writing a Flask application where users can join pools and compete against others within those pools (currently, pools and users are in a many to many relationship). Each user will need a rating for each pool that he/she is in (Elo Rating), and I'm not sure how to implement that into my existing structure. Any suggestions to implement it that either fit into my solution or change it would be appreciated.
(Right now, each user has a rating but it is shared amongst pools, which does not make sense for Elo)
def load_user(user_id):
return User.query.get(int(user_id))
pool_user = db.Table('pool_user',
db.Column('pool_id', db.Integer, db.ForeignKey('pool.id')),
db.Column('user_id', db.Integer, db.ForeignKey('user.id')))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
rating = db.Column(db.Integer, nullable=False)
pools = db.relationship('Pool', secondary=pool_user, backref=('members'))
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'])
return s.dumps({'user_id': self.id}).decode('utf-8')
#staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}', '{self.rating}')"
class Pool(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), nullable=False)
def __repr__(self):
return f"Pool: {self.name}"
For me, you should replace association table (pool_user) with association model (UserPool).
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
pools = db.relationship('UserPool')
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'])
return s.dumps({'user_id': self.id}).decode('utf-8')
#staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}'"
class Pool(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), nullable=False)
members = db.relationship('UserPool')
def __repr__(self):
return f"Pool: {self.name}"
class UserPool(db.Model):
pool_id = db.Column(db.Integer, db.ForeignKey('pool.id'), primary_key=True),
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
rating = db.Column(db.Integer, nullable=False)

Trouble adding comment relation to User table in flask-sqlalchemy

so I just got done following python YouTuber Corey Schafers tutorial on flask-sqlalchemy. I'm having problems modifying the DB we created. I'm trying to make a relation to my Comment table and User table. When a user posts a comment I want to store the user's name. So far I can't seem to link a user's comment on a post to the name of the author of the comment. This is the code that's relevant.
from datetime import datetime
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from smushd_site import db, login_manager
from flask_login import UserMixin
from flask import current_app
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model,UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
#comments_name = db.relationship('Comment', backref='author_comment', lazy=True)
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
#staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
comments = db.relationship('Comment', backref='author', lazy=True)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(100), nullable=False)
name = db.Column(db.String(100), nullable=False,default="stalin")
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
#poster_id = db.Column(db.String(100), db.ForeignKey('poster.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
#comment_name = db.Column(db.String(100), nullable=False)
#username = db.Column(db.String(100), db.ForeignKey('user.id'), nullable=False)
#comment_name = db.relationship('User', backref='author', lazy=True)
def __repr__(self):
return f"Comment('{self.body}', '{self.timestamp}')"
These are the link to the repo with the code and youtube series:
https://github.com/CoreyMSchafer/code_snippets/blob/master/Python/Flask_Blog/12-Error-Pages/flaskblog/models.py
https://www.youtube.com/watch?v=cYWiDiIUxQc&list=PL-osiE80TeTs4UjLw5MM6OjgkjFeUxCYH&index=4
Here is the code I wrote; it might help you. Feedback is just an example - you can do the same thing with Comment.
class User(db.Model, UserMixin):
__bind_key__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
email = db.Column(db.String(125), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(65), nullable=False)
about = db.Column(db.String(100), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
feedbacks = db.relationship('Feedback', backref='author', lazy=True)
create_account = db.Column(db.DateTime, nullable=False, default=datetime.now)
badges = db.Column(db.DateTime, nullable=False, default=datetime.now)
class Feedback(db.Model):
__bind_key__ = 'feedback'
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.now)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

Order of declaring classes in SqlAlchemy

I'm sory for this newby question, but I can't figure it out for a couple days and it is driving me nuts.
I'm building a small project in order to learn flask, SqlAlchemy and Postrges.
I have major problems with declaring classes in SqlAlchemy. I have already simplified models by removing all many-to-many relationships. However, now I have new problems even with one-to many relationships, although I think I have tried all the possible options. Maybe there's a typo that I keep on overlooking, or I don't grasp something fundamental. Please let me know...
So, I have classes declared as follows in my models.py:
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
date_registered = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
role = db.Column(db.Integer, nullable=False)
role_exp_date = db.Column(db.DateTime)
#o2o
personal_datas = db.relationship('PersonalData', uselist=False, backref='user', lazy=True)
persons = db.relationship('Person', uselist=False, backref='user', lazy=True)
#o2m
posts = db.relationship('Post', backref='author', lazy=True)
comments = db.relationship('PostComment', backref='author', lazy=True)
projects_owned = db.relationship('ConstrProject', backref='owner', lazy=True)
attachments = db.relationship('Attachment', backref='author', lazy=True)
def __repr__(self):
return f"{self.username} ({self.email})"
class PersonalData(db.Model):
id = db.Column(db.Integer, primary_key = True)
date_birth = db.Column(db.DateTime)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
interests = db.Column(db.Text)
experties = db.Column(db.Text) #Потом сделать отдельную таблицу...
#o2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
#o2m
class Person(db.Model):
id = db.Column(db.Integer, primary_key = True)
first_name = db.Column(db.String(30), nullable=False)
middle_name = db.Column(db.String(40), nullable=False)
last_name = db.Column(db.String(60), nullable=False)
email = db.Column(db.String(120))
license = db.Column(db.String(120))
address = db.Column(db.String(240))
telephone = db.Column(db.String(30))
#o2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
#o2m
signers = db.relationship('Signer', backref='person', lazy=True)
def __repr__(self):
return f"{self.last_name.Capitalize} {self.first_name[0].Upper}. {self.middle_name[0].Upper}."
class ConstrProject(db.Model):
__tablename__ = 'constrproject'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(120), nullable=False, default='New Project')
full_title = db.Column(db.Text, default='New Project')
notes = db.Column(db.Text)
public = db.Column(db.Boolean, default=True) #? check expamples
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
date_last_edit = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
document_template = db.Column(db.Integer, nullable=False, default=1) #later to m2m
print_settings = db.Column(db.Integer, nullable=False, default=1) #later to m2m
address = db.Column(db.String(240))
#o2m
documents = db.relationship('Document', backref='project', lazy=True)
#m2o
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) #+ #default = CurrentUser
developer_id = db.Column(db.Integer, db.ForeignKey('company.id'))
main_contractor_id = db.Column(db.Integer, db.ForeignKey('company.id'))
architect_id = db.Column(db.Integer, db.ForeignKey('company.id'))
subcontractor_id = db.Column(db.Integer, db.ForeignKey('company.id'))
other_id = db.Column(db.Integer, db.ForeignKey('company.id'))
developer = db.relationship('Company', foreign_keys=[developer_id], back_populates='constr_projects_developed')
main_contractor = db.relationship('Company', foreign_keys=[main_contractor_id], back_populates='constr_projects_main_contracts')
architect = db.relationship('Company', foreign_keys=[architect_id], back_populates='constr_projects_architect')
subcontractor = db.relationship('Company', foreign_keys=[subcontractor_id], back_populates='constr_projects_subcontracts')
other = db.relationship('Company', foreign_keys=[other_id], back_populates='constr_projects_other')
tech_control_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
main_contractor_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
architect_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
subcontractor_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
other_reps_id = db.Column(db.Integer, db.ForeignKey('signer.id'), nullable=False)
tech_control_reps = db.relationship('Signer', foreign_keys=[tech_control_reps_id], back_populates='tech_control_projects')
main_contractor_reps = db.relationship('Signer', foreign_keys=[main_contractor_reps_id], back_populates='main_contractor_projects')
architect_reps = db.relationship('Signer', foreign_keys=[architect_reps_id], back_populates='architect_projects')
subcontractor_reps = db.relationship('Signer', foreign_keys=[subcontractor_reps_id], back_populates='subcontractor_projects')
other_reps = db.relationship('Signer', foreign_keys=[other_reps_id], back_populates='others_projects')
def __repr__(self):
return f"Site: {self.name}, (id{self.id})"
class Signer(db.Model):
id = db.Column(db.Integer, primary_key = True)
decree = db.Column(db.String(120))
job_title = db.Column(db.String(120))
date_duty_start = db.Column(db.DateTime)
date_duty_end = db.Column(db.DateTime)
#o2m
person_id = db.Column(db.Integer, db.ForeignKey('person.id'), nullable=False)
company_id = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False)
#m2o
tech_control_projects = db.relationship('ConstrProject', back_populates='tech_control_reps')
main_contractor_projects = db.relationship('ConstrProject', back_populates='main_contractor_reps')
architect_projects = db.relationship('ConstrProject', back_populates='architect_reps')
subcontractor_projects = db.relationship('ConstrProject', back_populates='subcontractor_reps')
others_projects = db.relationship('ConstrProject', back_populates='other_reps')
def __repr__(self):
return f"{self.job_title} as per {self.decree}." #название компании как подтянуть
class Company(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(60))
full_title = db.Column(db.String(240))
tin = db.Column(db.Integer)
kpp = db.Column(db.Integer)
ogrn = db.Column(db.Integer)
email = db.Column(db.String(120))
address = db.Column(db.String(240))
telephone = db.Column(db.String(30))
#o2m
license_number = db.Column(db.String(40), nullable = False)
license_date_issued = db.Column(db.DateTime)
license_category = db.Column(db.String(120), default = '2nd')
license_issued_by = db.Column(db.String(120))
license_issued_by_tin = db.Column(db.Integer)
license_issued_by_kpp = db.Column(db.Integer)
license_issued_by_ogrn = db.Column(db.Integer)
signers = db.relationship('Signer', backref='company', lazy=True)
constr_projects_developed = db.relationship('ConstrProject', back_populates='developer')
constr_projects_main_contracts = db.relationship('ConstrProject', back_populates='main_contractor')
constr_projects_architect = db.relationship('ConstrProject', back_populates='architect')
constr_projects_subcontracts = db.relationship('ConstrProject', back_populates='subcontractor')
constr_projects_other = db.relationship('ConstrProject', back_populates='other')
def __repr__(self):
return f"{self.name}"
class Post(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
#o2m
comments = db.relationship('PostComment', backref='Post', lazy=True)
#m2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
class PostComment(db.Model):
id = db.Column(db.Integer, primary_key = True)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
#m2o
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
def __repr__(self):
return f"Comment('{self.id}', '{self.date_posted}')"
class Document(db.Model):
id = db.Column(db.Integer, primary_key = True)
type = db.Column(db.String(60), nullable=False, default='АОСР')
date_last_edit = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
notes = db.Column(db.Text)
public = db.Column(db.Boolean, default=True)
number = db.Column(db.String(20), nullable=False)
date = db.Column(db.DateTime, default=datetime.utcnow)
job_name = db.Column(db.Text) #? обязательный? на каком этапе делать проверку?
job_place = db.Column(db.String(200))
date_job_start = db.Column(db.DateTime, default=datetime.utcnow)
date_job_end = db.Column(db.DateTime, default=datetime.utcnow)
regulations = db.Column(db.Text)
next_job_allowed = db.Column(db.String(240))
attachments_user_defined = db.Column(db.Text)
#o2m
attachments = db.relationship('Attachment', backref='document', lazy=True)
#m2o
project_id = db.Column(db.Integer, db.ForeignKey('constrproject.id'), nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
#m2m
arch_docs = db.Column(db.Text)
building_materials = db.Column(db.Text)
work_drawings = db.Column(db.Text)
def __repr__(self):
return f"АОСР ('{self.number}', '{self.job_name} {self.job_place}', '{self.project}' )"
class Attachment(db.Model):
id = db.Column(db.Integer, primary_key = True)
type_of_document = db.Column(db.String(60), nullable=False, default="QAC")
number = db.Column(db.String(50), nullable=False)
date = db.Column(db.DateTime)
date_valid_start = db.Column(db.DateTime)
date_valid_end = db.Column(db.DateTime)
contents = db.Column(db.Text)
type_of_file = db.Column(db.String(10), nullable=False, default = 'jpg')
image_file = db.Column(db.String(20), nullable=False)
#m2o
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
document_id = db.Column(db.Integer, db.ForeignKey('document.id'), nullable=False)
def __repr__(self):
if self.text:
return f'{self.text}'
return f'+{self.type_of_document} id{self.id} ({self.type_of_file})'
I cannot understand why, when I try to create an instance of a "Document"
I get errors like this:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
condition between parent/child tables on relationship
Signer.tech_control_projects - there are multiple foreign key paths
linking the tables. Specify the 'foreign_keys' argument, providing a
list of those columns which should be counted as containing a foreign
key reference to the parent table.
or
sqlalchemy.exc.InvalidRequestError: When initializing mapper
Mapper|ConstrProject|constrproject, expression 'tech_control_reps_id'
failed to locate a name ("name 'tech_control_reps_id' is not
defined"). If this is a class name, consider adding this
relationship() to the class
after both dependent classes have been defined.
I haven't even tried to create these classes. Adding "foreign_keys" doesn't seem to help either. all relationships declared as strings. I tried to use lambda's also without success.
Nevertheless moving the order of class declearations alters the error messages i get...
I cannot find any good examples (resources) of more complicated databases with multiple many-to-many and one-to-many relationships in Each class. Usually examples are very basic and obvious.
So I would really appreciate if you post links to such projects or tutorials.
I wanted to learn some of it myself so I created a working example with one-to-one and multiple one-to-many relationships based on your code (User, Person, Post and Comment classes). I hope it will be a good (simple but not trivial) example for you.
'''SQLAlchemy one-to-one and one-to-many SSCCE'''
import sqlalchemy
import sqlalchemy.ext.declarative
from passlib.hash import pbkdf2_sha256
Base = sqlalchemy.ext.declarative.declarative_base()
class User(Base):
__tablename__ = 'users'
user_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
username = sqlalchemy.Column(sqlalchemy.String(20), unique=True, nullable=False)
email = sqlalchemy.Column(sqlalchemy.String(120), unique=True, nullable=False)
password = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
registered = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
#o2o
person = sqlalchemy.orm.relationship(
'Person',
uselist=False,
back_populates='user',
lazy='joined'
)
#o2m
posts = sqlalchemy.orm.relationship('Post', back_populates='user')
comments = sqlalchemy.orm.relationship('Comment', back_populates='user')
def __repr__(self):
return f'{self.username} ({self.email})'
class Person(Base):
__tablename__ = 'persons'
person_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
primary_key=True
)
first_name = sqlalchemy.Column(sqlalchemy.String(30), nullable=False)
middle_name = sqlalchemy.Column(sqlalchemy.String(40), nullable=False)
last_name = sqlalchemy.Column(sqlalchemy.String(60), nullable=False)
#o2o
user = sqlalchemy.orm.relationship('User', back_populates='person', lazy='joined')
def __repr__(self):
return (
f'{self.last_name.upper()}'
f' {self.first_name[:1].upper()}.'
f' {self.middle_name[:1].upper()}.'
)
class Post(Base):
__tablename__ = 'posts'
post_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
title = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
posted = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
content = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
#o2m
comments = sqlalchemy.orm.relationship('Comment', back_populates='post')
#m2o
user_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
nullable=False
)
user = sqlalchemy.orm.relationship('User', uselist=False, back_populates='posts', lazy='joined')
def __repr__(self):
return f'Post({self.title!r}, {self.posted!r})'
class Comment(Base):
__tablename__ = 'comments'
comment_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
posted = sqlalchemy.Column(
sqlalchemy.DateTime(timezone=True),
nullable=False,
server_default=sqlalchemy.func.now()
)
content = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
#m2o
user_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('users.user_id'),
nullable=False
)
user = sqlalchemy.orm.relationship(
'User',
uselist=False,
back_populates='comments',
lazy='joined'
)
post_id = sqlalchemy.Column(
sqlalchemy.Integer,
sqlalchemy.ForeignKey('posts.post_id'),
nullable=False
)
post = sqlalchemy.orm.relationship(
'Post',
uselist=False,
back_populates='comments',
lazy='joined'
)
def __repr__(self):
return f'Comment({self.comment_id!r}, {self.posted!r})'
def main():
engine = sqlalchemy.create_engine(
'postgresql+psycopg2:///stack',
echo=True,
server_side_cursors=True,
use_batch_mode=True
)
Base.metadata.create_all(engine)
Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()
session.commit()
try:
the_user = session.query(User).filter(User.username == 'example').one()
except sqlalchemy.orm.exc.NoResultFound:
the_user = User(
username='example',
email='example#example.com',
password=pbkdf2_sha256.hash('correct horse battery staple')
)
the_user.person = Person(first_name='Ex', middle_name='', last_name='Ample')
session.add(the_user)
print(the_user)
print(the_user.person)
if not the_user.posts:
the_user.posts.append(Post(title='First post', content='Lorem ipsum'))
session.commit()
print(the_user.posts[0])
if not the_user.posts[0].comments:
the_user.posts[0].comments.append(Comment(content='Me too', user=the_user))
session.commit()
print(the_user.posts[0].comments[0])
if __name__ == '__main__':
main()
Several comments:
I don't think it is easy to have foreign-keys both ways for a mandatory one-to-one relationship.
I made both User and Person use the same id numbers, as they are one-to-one.
I made the PostgreSQL now() as the default value for timestamps, instead of client-side utcnow.
I made the timestamps use "timestamp with timezone" type - the "timestamp" type (without timezone) is an abomination.
"user" is a bad name for a table, as this is also a keyword in PostgreSQL, so I changed it to "users". Other tables also changed to plural form for consistency.
A secure password storage is a must.
I used back_populates consistently, as it is more explicit and works better with static code analyzers than backref.

flask web ,current_user.role is None ,but table roles is not None

class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.Integer, unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
def can(self, permissions):
print(self.role) #None
return self.role is not None and (self.role.permissions & permissions) == permissions
#main.route('/',methods=['GET', 'POST'])
def index():
form = PostForm()
print(current_user.role) #None
print(current_user.can(Permission.WRITE_ARTICLES)) #False
if current_user.can(Permission.WRITE_ARTICLES) and form.validate_on_submit():
post = Post(body=form.body.data, author=current_user._get_current_object())
db.session.add(post)
return redirect(url_for('.index'))
posts = Post.query.order_by(Post.timestamp.desc()).all()
return render_template('index.html', form=form, posts=posts)
sqlite> .tables
alembic_version posts roles users
sqlite> select * from roles;
1|Administrator|0|255
2|Moderator|0|15
3|User|1|7
there is data in roles, but print(current_user.role) is None,and When I call the can function in class User, print(self.role) is also None.
I can't understand why self.role is None?

Categories

Resources