Sqlalchemy: Numeric Value out of range - python

When i try to add user with BIG INT, psycopg2 throws Numberic Value out of range error.
but still BIGINT is my data type in Column of my table and in local postgresql database.
Edit1: I have added the source code for chat_members model.
My table Schema code
class Users(BASE):
__tablename__ = "users"
user_id = Column(BigInteger, primary_key=True)
username = Column(UnicodeText)
def __init__(self, user_id, username=None):
self.user_id = user_id
self.username = username
def __repr__(self):
return "<User {} ({})>".format(self.username, self.user_id)
class Chats(BASE):
__tablename__ = "chats"
chat_id = Column(String(14), primary_key=True)
chat_name = Column(UnicodeText, nullable=False)
def __init__(self, chat_id, chat_name):
self.chat_id = str(chat_id)
self.chat_name = chat_name
def __repr__(self):
return "<Chat {} ({})>".format(self.chat_name, self.chat_id)
class ChatMembers(BASE):
__tablename__ = "chat_members"
priv_chat_id = Column(Integer, primary_key=True)
# NOTE: Use dual primary key instead of private primary key?
chat = Column(
String(14),
ForeignKey("chats.chat_id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False,
)
user = Column(
BigInteger,
ForeignKey("users.user_id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False,
)
__table_args__ = (UniqueConstraint("chat", "user", name="_chat_members_uc"),)
def __init__(self, chat, user):
self.chat = chat
self.user = user
def __repr__(self):
return "<Chat user {} ({}) in chat {} ({})>".format(
self.user.username,
self.user.user_id,
self.chat.chat_name,
self.chat.chat_id,
)
Users.__table__.create(checkfirst=True)
Chats.__table__.create(checkfirst=True)
ChatMembers.__table__.create(checkfirst=True)
code which throws error:
def update_user(user_id, username, chat_id=None, chat_name=None):
with INSERTION_LOCK:
user = SESSION.query(Users).get(user_id)
if not user:
user = Users(user_id, username)
SESSION.add(user)
SESSION.flush()
else:
user.username = username
if not chat_id or not chat_name:
SESSION.commit()
return
chat = SESSION.query(Chats).get(str(chat_id))
if not chat:
chat = Chats(str(chat_id), chat_name)
SESSION.add(chat)
SESSION.flush()
else:
chat.chat_name = chat_name
member = (
SESSION.query(ChatMembers)
.filter(ChatMembers.chat == chat.chat_id, ChatMembers.user == user.user_id)
.first()
)
if not member:
chat_member = ChatMembers(chat.chat_id, user.user_id)
SESSION.add(chat_member)
SESSION.commit()
my init.py file:
def start() -> scoped_session:
engine = create_engine(DB_URI, client_encoding="utf8")
BASE.metadata.bind = engine
BASE.metadata.create_all(engine)
return scoped_session(sessionmaker(bind=engine, autoflush=False))
BASE = declarative_base()
SESSION = start()
Tracelog:
sqlalchemy.exc.DataError: (psycopg2.errors.NumericValueOutOfRange) integer out of range
[SQL: INSERT INTO chat_members (chat, "user") VALUES (%(chat)s, %(user)s) RETURNING chat_members.priv_chat_id]
[parameters: {'chat': '-1001779301880', 'user': 5030277858}]
(Background on this error at: https://sqlalche.me/e/14/9h9h)

Related

User with role Product not in ['Customer', 'Admin'] in fastApi

I getting error related the role & I don't know What I mistake.
enter image description here
enter image description here
Database Models:
class Role(Base):
__tablename__ = "role"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), index=True,default="Product")
role_onwer = relationship("User",back_populates="role",uselist=False)
role_onwer1 = relationship("Customer",back_populates="role1",uselist=False)
def __repr__(self):
return f'<Role {self.name}>'
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50))
email = Column(String(255), index=True,unique=True)
password = Column(String(80))
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(
DateTime,
default=datetime.datetime.utcnow,
onupdate=datetime.datetime.utcnow,
)
last_login = Column(DateTime, nullable=True)
user = relationship("Customer",back_populates="user_onwer",uselist=False)
restaurant = relationship("Restaurant",back_populates="restaurant_onwer",uselist=False)
role_id = Column(Integer, ForeignKey('role.id'))
role = relationship("Role",back_populates="role_onwer",uselist=False)
def __repr__(self):
return f'<User {self.email}>'
class Customer(Base):
__tablename__ = "customer"
id = Column(Integer, primary_key=True)
name = Column(String(255))
phone = Column(String(255))
address = Column(String(255))
city = Column(String(255))
zipCode = Column(String(255))
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(
DateTime,
default=datetime.datetime.utcnow,
onupdate=datetime.datetime.utcnow,
)
user_id = Column(Integer, ForeignKey("user.id"))
role_id = Column(Integer, ForeignKey('role.id'))
role1 = relationship("Role",back_populates="role_onwer1",uselist=False)
user_onwer = relationship("User",back_populates="user",uselist=False)
orders = relationship("Order", back_populates="order_onwer",uselist=False)
def __repr__(self):
return f'<Customer {self.name}>'
pydantic Models
T = TypeVar('T')
class Response(GenericModel, Generic[T]):
code: str
status: str
message: str
result: Optional[T]
# Customer Request Schemas
class CustomerSchema(BaseModel):
username: str
email: EmailStr
password: str
name: str
phone: str
address: str
city: str
zipCode: str
Crud funtions: customerController
def get_customer_by_id(db: Session, customer_id: int):
return db.query(Customer).filter(Customer.id == customer_id).first()
# This one i have implemented for you
def create_customer(db: Session, customer: CustomerSchema):
new_role = Role()
db.add(new_role)
db.commit()
db.refresh(new_role)
role_ids = new_role.id
new_user = User(username=customer.username, email=customer.email, password=Hash.bcrypt(customer.password),role_id =role_ids)
# new_user = User(username=customer.username, email=customer.email, password=Hash.bcrypt(customer.password),
# role_id=2)
db.add(new_user)
db.commit()
db.refresh(new_user)
user_ids = new_user.id
print(user_ids)
_customer = Customer(name=customer.name, phone=customer.phone, address=customer.address,
city=customer.city, zipCode=customer.zipCode,user_id=user_ids,role_id =role_ids)
db.add(_customer)
db.commit()
db.refresh(_customer)
return _customer
def remove_customer(db: Session, customer_id: int):
_customer = get_customer_by_id(db=db, customer_id=customer_id)
db.delete(_customer)
db.commit()
def update_customer(db: Session, customer_id: int, name: str, email: str, phone: int, customerID: str, address: str,
city: str, zipCode: str):
_customer = get_customer_by_id(db=db, customer_id=customer_id)
_customer.name = name
_customer.email = email
_customer.phone = phone
_customer.customerID = customerID
_customer.address = address
_customer.city = city
_customer.zipCode = zipCode
db.commit()
db.refresh(_customer)
return _customer
customerRouter:
#router.get('/')
async def get(db: Session = Depends(get_db)):
_customer = customerController.get_customer(db, 0, 100)
return Response(code=200, status='OK', message='Success fetch all data', result=_customer).dict(exclude_none=True)
AuthController
class RoleChecker:
def __init__(self, allowed_roles: List):
self.allowed_roles = allowed_roles
def __call__(self, user: schemas.User = Depends(get_current_user)):
if user.role.name not in self.allowed_roles:
print(f"User with role {user.role.name} not in {self.allowed_roles}")
raise HTTPException(status_code=403, detail="Operation not permitted")
return user
customer_access = RoleChecker(['Customer', 'Admin'])
Thank you
I need to have so user cannot retrieve data without being logged in.
and a customer is a user who buys stuff and they may only have the following access:
/customer BY ID:
Read (only they own information)
Update:(only your own data)

AttributeError: 'Session' object has no attribute 'session'

I am creating an endpoint that will effect a reversal using fastApi with python.I have an endpoint that takes in an id via post request & calls a reverse function on the transaction model. But I get the error AttributeError: 'Session' object has no attribute 'session' on 'db.session.add(transaction)' . I am not sure where this is coming from.
Transaction model
class Transaction(Base):
__tablename__ = "transactions"
id = Column(Integer, primary_key=True, index=True)
uuid = Column(UUID(as_uuid=True), nullable=False, default=uuid.uuid4)
amount = Column(Numeric(18, 2))
type = Column(
Enum(TransactionTypes, name="transaction_trans_types"), nullable=False
)
wallet_type = Column(
Enum(WalletTypes, name="transaction_wallet_types"), nullable=False
)
created_when = Column(DateTime(timezone=True), server_default=func.now())
payment_ref = Column(String, nullable=False)
running_balance = Column(Numeric(18, 2))
currency = Column(String, default="KES")
notes = Column(String)
paid_by = Column(UUID(as_uuid=True), ForeignKey("patients.uuid"), nullable=True,)
patient_uuid = Column(UUID(as_uuid=True), ForeignKey("patients.uuid"))
wallet_uuid = Column(UUID(as_uuid=True), ForeignKey("wallets.uuid"))
paid_by_names = Column(String)
def reverse(self,db: Session,notes:str =None,):
transaction =Transaction(amount =self.amount,type= self.type,wallet_type = self.wallet_type,payment_ref = self.payment_ref,
notes= notes )
db.session.add(transaction)
db.session.commit()
db.session.refresh(transaction)
reversal = Reversal(transaction_uuid=transaction.uuid,reversed_transaction_uuid= self.reversed_transaction_uuid)
db.session.add(reversal)
db.session.commit()
db.session.refresh(reversal)
return transaction
Reversal Model
class Reversal(Base):
__tablename__ = "reversals"
id = Column(Integer, primary_key=True, index=True)
transaction_uuid = Column(UUID(as_uuid=True), ForeignKey("transactions.uuid"))
reversed_transaction_uuid = Column(UUID(as_uuid=True),ForeignKey("transactions.uuid"))
__table_args__ = (
UniqueConstraint("reversed_transaction_uuid"),
)
Endpoint
#router.post("/{transaction_id}/reverse",)
async def reverse_transaction(
*,
db: Session = Depends(deps.get_db),
transaction_id: int,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Reverse transaction
"""
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not allowed to reverse transactions",
)
try:
transaction = (
db.query(Transaction).filter(Transaction.id == transaction_id).scalar()
)
transaction.reverse(db,transaction)
except NoResultFound:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Not found",
)
return transaction
This is my deps.db
def get_db() -> Generator:
try:
db = SessionLocal()
yield db
finally:
db.close()
The most important part would be to see how deps.get_db() looks like.
But according to your type hints I guess, this already gives you a Session. So instead of db.session in your reverse method, simply use db.

Problem Using QuerySelectMultipleField in Flask-Admin Edit Form

I'm newly come to Flask-Admin, and I'm trying to customize a model edit form. My User model has a roles attribute which is a relationship through the role_users table to Role.name, with a foreign key constraint.
Everything works so far, except that the Flask-Admin default User edit form renders roles as a string field. I'd like to render it as a QuerySelectMultipleField. My models are:
from flask import current_app
from flask_login import UserMixin
from werkzeug.security import check_password_hash, generate_password_hash
from app import db, login_manager
roles = db.Table(
'role_users',
db.Column('user_id', db.String(64), db.ForeignKey('users.username')),
db.Column('role_id', db.String(80), db.ForeignKey('roles.name')),
db.PrimaryKeyConstraint('user_id', 'role_id')
)
class User(UserMixin, db.Model):
__tablename__ = 'users'
username = db.Column(db.String(64), primary_key=True)
password_hash = db.Column(db.String(128))
firstname = db.Column(db.String(64))
lastname = db.Column(db.String(64))
roles = db.relationship('Role', secondary=roles, backref=db.backref('users', lazy='dynamic'))
def __init__(self, username='', password=''):
default = Role.query.filter_by(name='View_contact').one()
self.roles.append(default)
self.username = username
self.password = password
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#property
def password(self):
raise AttributeError('Password is not a readable attribute.')
#password.setter
def password(self, password):
self.set_password(password)
# Required for user_loader with non-integer User PK not named 'id'
def get_id(self):
return self.username
def grant_role(self, role_name):
if not self.has_role(role_name):
role = Role.query.filter_by(name=role_name).first()
self.roles.append(role)
db.session.commit()
def revoke_role(self, role_name):
if self.has_role(role_name):
role = Role.query.filter_by(name=role_name).first()
self.roles.remove(role)
def has_role(self, role_name):
for role in self.roles:
if role.name == role_name:
return True
return False
#login_manager.user_loader
def load_user(username):
return User.query.get(str(username))
class Role(db.Model):
__tablename__ = 'roles'
role_list = [
'View_contact',
'Add_contact',
'Edit_contact',
'Delete_contact',
'View_user',
'Add_user',
'Edit_user',
'Delete_user',
'Admin',
]
name = db.Column(db.String(80), primary_key=True)
description = db.Column(db.String(255))
def __init__(self, name):
self.name = name
def __repr__(self):
return '<Role {}>'.format(self.name)
#classmethod
def load_roles(cls):
for role_name in cls.role_list:
role = Role.query.filter_by(name=role_name).first()
if role is None:
role = Role(name=role_name)
db.session.add(role)
db.session.commit()
My custom ModelView is
from flask_admin.contrib.sqla import ModelView
from flask_admin.contrib.sqla.fields import QuerySelectMultipleField, QuerySelectField
from flask_admin.form import Select2TagsWidget, Select2Widget
from wtforms import PasswordField
from app import db
from app.models import Role, User
class UserView(ModelView):
column_display_pk = True
form_extra_fields = {
'password': PasswordField('Password'),
'role_sel': QuerySelectMultipleField(
label='Roles',
query_factory=lambda: Role.query.all,
widget=Select2TagsWidget()
)
}
form_columns = (
'username',
'password',
'firstname',
'lastname',
'role_sel',
)
def on_model_change(self, form, User, is_created):
if form.password.data != '':
User.set_password(form.password.data)
but when I try to access admin/user/new/ or admin/user/edit Flask throws AttributeError: 'QuerySelectMultipleField' object has no attribute '_value'.
If I try changing from QuerySelectMultipleField & Select2TagsWidget to QuerySelectField & Select2Widget Flask throws TypeError: 'method' object is not iterable.
Can someone tell me what I'm doing wrong? Is _value() a method I need to implement? I'm using Flask-Admin 1.5.8.
First of all, i think you should use another naming system for your tables:
# change this to roles_users
roles = db.Table(
'role_users',
db.Column('user_id', db.String(64), db.ForeignKey('users.username')),
db.Column('role_id', db.String(80), db.ForeignKey('roles.name')),
db.PrimaryKeyConstraint('user_id', 'role_id')
)
Now, moving to a possible solution:
Even though you think you dont need an id attribute (or column) on your User and Rolemodels, it is kinda default to use id as the primary key for models. Many extensions and frameworks will work "as is" if you just follow the patterns.
I think that what is going wrong with your implementation, is that FlaskAdmin's ModelView is having troubles when defining the Roles model primary key.
Try the following code:
class Role(db.Model):
...
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True)
...
roles = db.Table(
'role_users',
db.Column('user_id', db.String(64), db.ForeignKey('users.username')),
db.Column('role_id', db.String(80), db.ForeignKey('roles.id')),
db.PrimaryKeyConstraint('user_id', 'role_id')
)
and remove the role_sel from your form_args, and form_columns in the UserView.
FlaskAdmin should guess that the User.roles is a many-to-many field and render it as a multi select field.
your error is where your secondary needs to be pointed to the
role_users table where the relationship is kept track
lass User(UserMixin, db.Model):
__tablename__ = 'users'
username = db.Column(db.String(64), primary_key=True)
password_hash = db.Column(db.String(128))
firstname = db.Column(db.String(64))
lastname = db.Column(db.String(64))
roles = db.relationship('Role', secondary=role_users)

User.query.filter_by(id=user_id).first() and User.query.get(user_id) returns None in Flask Sql Alchemy

I have run into an error with querying the user according to the user_id passed along the parameter of my route. I have used the same method in many other functions and none of them throws any errors. I have users in my database with the corresponding ids. This query shouldn't detect any errors but it does and would really appreciate any help.
the target_user variable in the function gets assigned None and that gives me the error
"NoneType' object has no attribute 'id'"
This is the User Model
followers = db.Table('followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
)
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
user_handle = db.Column(db.String(15), unique=True)
display_name = db.Column(db.String(30), nullable=False)
password = db.Column(db.String(20), nullable=False)
profile_picture_url = db.Column(db.String(100), nullable=True, default="./static/user_media/default_egg.png")
# profile_description = db.Column(db.String(140), nullable=True)
tweets = db.relationship('Tweet', backref="owner")
# relationships
liked = db.relationship('LikeTweet', foreign_keys="LikeTweet.liked_by",
backref="user", lazy="dynamic")
def like_tweet(self, tweet):
if not self.has_liked_tweet(tweet):
like = LikeTweet(liked_by=self.id, liked_tweet=tweet.id)
db.session.add(like)
def unlike_tweet(self, tweet):
if self.has_liked_tweet(tweet):
LikeTweet.query.filter_by(
liked_by=self.id,
liked_tweet=tweet.id).delete()
def has_liked_tweet(self, tweet):
return LikeTweet.query.filter(
LikeTweet.liked_by == self.id,
LikeTweet.liked_tweet == tweet.id).count() > 0
followed = db.relationship('User', secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'),
lazy='dynamic')
def follow(self, user):
if not self.is_following(user):
self.followed.append(user)
return self
def unfollow(self, user):
if self.is_following(user):
self.followed.remove(user)
return self
def is_following(self, user):
return self.followed.filter(followers.c.followed_id == user.id).count() > 0
This is the function that I am making the query from
#main.route('/follow/<user_id>')
#login_required
def follow_user(user_id):
referrer = request.headers.get("Referer")
target_user = User.query.filter_by(id=user_id).first()
print(target_user)
if current_user.is_following(target_user):
current_user.unfollow(target_user)
db.session.commit()
else:
current_user.follow(target_user)
db.session.commit()
return redirect(referrer)

SQLAlchemy / WTForms - QuerySelectField

I'm using WTForms with the SQLAlchemy extension on a Pyramid application.
My session is:
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
My model is:
class Client(Base):
__tablename__ = 'client'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(Unicode(48))
street = Column(Unicode(48))
city = Column(Unicode(32))
task = relationship("Task", backref="client")
#classmethod
def active(cls):
return DBSession.query(Client).options(load_only("id", "name")).order_by(sa.desc(Client.name)).filter(Client.status == True)
class Task(Base):
__tablename__ = 'task'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(48))
status = Column(Boolean)
client_id = Column(Integer, ForeignKey('client.id'))
My form is:
def enabled_client():
return Client.active()
class TaskCreateForm(ModelForm):
name = TextField('Task name', [validators.Length(min=1, max=48)], filters=[strip_filter])
status = BooleanField('Status')
client_id = QuerySelectField('Client', query_factory=enabled_client, get_label='name', allow_blank=False)
My view is:
#view_config(route_name='task_action', match_param='action=create', renderer='arx:templates/task_edit.mako', permission='edit')
def task_create(request):
task = Task()
form = TaskCreateForm(request.POST)
if request.method == 'POST' and form.validate():
form.populate_obj(task)
DBSession.add(task)
return HTTPFound(location=request.route_url('home'))
return {'form':form, 'action':request.matchdict.get('action')}
Form displays select box with proper Client names but the problem emerges when I'm trying to submit form. WTForm should use real ID of Client but it passes SQLAlchemy object eg:
<arx.models.Client object at 0x7fdfb139ddd0>
What am I doing wrong?
My form was too specific (it should be client instead of client_id), so my working code looks like this:
Session:
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
Model:
class Client(Base):
__tablename__ = 'client'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(Unicode(48))
street = Column(Unicode(48))
city = Column(Unicode(32))
task = relationship("Task", backref="client")
#classmethod
def active(cls):
return DBSession.query(Client).options(load_only("id", "name")).order_by(sa.desc(Client.name)).filter(Client.status == True)
class Task(Base):
__tablename__ = 'task'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(48))
status = Column(Boolean)
client_id = Column(Integer, ForeignKey('client.id'))
Form:
def enabled_client():
return Client.active()
class TaskCreateForm(ModelForm):
name = TextField('Task name', [validators.Length(min=1, max=48)], filters=[strip_filter])
status = BooleanField('Status')
client = QuerySelectField('Client', query_factory=enabled_client, get_label='name', allow_blank=False)
View:
#view_config(route_name='task_action', match_param='action=create', renderer='arx:templates/task_edit.mako', permission='edit')
def task_create(request):
task = Task()
form = TaskCreateForm(request.POST)
if request.method == 'POST' and form.validate():
form.populate_obj(task)
DBSession.add(task)
return HTTPFound(location=request.route_url('home'))
return {'form':form, 'action':request.matchdict.get('action')}

Categories