How to get sqlalchemy relationship list in pydantic model? - python

when I try to get organization by id (inn) in devices_list field is null (device is exist):
{
inn: 8481406044,
organization_name: "slava bebrow",
devices_list: null
}
models.py:
class Organization(Base):
__tablename__ = "organizations_table"
inn = Column(BigInteger, primary_key=True, index=False)
organization_name = Column(String, nullable=False, unique=True)
devices = relationship("Device", backref="organizations_table")
class Device(Base):
__tablename__ = "devices_table"
uuid = Column(String, primary_key=True, index=False)
device_name = Column(String, nullable=False, unique=True)
organization_id = Column(BigInteger, ForeignKey("organizations_table.inn"), nullable=True)
pydantic_models.py:
class OrganizationBase(BaseModel):
inn: int
organization_name: str
class Config:
orm_mode = True
class Organization(OrganizationBase):
devices_list: list['DeviceBase'] = None
class DeviceBase(BaseModel):
uuid: str
device_name: str
organization_id: int | None
class Config:
orm_mode = True
functions to get organization:
def get_organization(db: Session, organization_id: int):
db_organization = db.query(models.Organization).filter(models.Organization.inn == organization_id).first()
if db_organization is None:
raise HTTPException(status_code=404, detail="Organization not found")
return db_organization
when i try to print(db_organization.devices[0].uuid) i get a list with objects
#app.get("/organizations/{organization_id}", response_model=pydantic_models.Organization)
def get_organization(organization_id, db: Session = Depends(get_db)):
return al.get_organization(db=db, organization_id=organization_id)
I think problem is in pydantic model, but i don't know how to fix it.
I expect a list of devices in field, not null

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)

Populate Pydantic schema based on model ID

I want to map backer_id which is a primary key in my model to all the information related to that user (as defined in UserInProject schema) using Pydantic.
Pydantic file:
class UserInProject(BaseModel):
email: EmailStr
full_name: str
id: int
class Config:
orm_mode = True
class TransactionBase(BaseModel):
quantity: int
amount: float
currency: Currency
class TransactionIn(TransactionBase):
project_id: int
class TransactionOut(BaseModel):
id: int
date_ordered: datetime
backer: "UserInProject"
My model:
class BackerProjectOrder(Base):
__tablename__ = "backers_projects_orders"
id = Column(
Integer, primary_key=True, index=True, autoincrement=True, nullable=False
)
backer_id = Column(ForeignKey("users.id"), index=True, primary_key=True)
...
My API:
#router.post(
"/", status_code=status.HTTP_201_CREATED, response_model=schema.TransactionOut
)
def create_transaction(
transaction: schema.TransactionIn,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
new_transaction = models.BackerProjectOrder(**transaction_dict, backer_id = current_user.id)
db.add(new_transaction)
db.commit()
db.refresh(new_transaction)
And it currently gives me this error:
pydantic.error_wrappers.ValidationError: 1 validation error for TransactionOut
response -> backer
field required (type=value_error.missing)
How can I ask Pydantic to map the backer_id field to the UserInProject schema? Is it possible at all?

Trying to add a record to tables with many-to-many relationship using POST - FastAPI + SQLalchemy

I have some pydantic and SQLalchemy models
game_users = Table('game_users', Base.metadata,
Column('game_id', ForeignKey('games.id'), primary_key=True),
Column('user_id', ForeignKey('users.id'), primary_key=True)
)
class Game(Base):
__tablename__ = 'games'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
users = relationship("User", secondary="game_users", back_populates='games')
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
age = Column(Integer)
email = Column(String, nullable=False, unique=True)
games = relationship("Game", secondary="game_users", back_populates='users')
class UserBase(BaseModel):
id: int
name: str
age: int = Query(ge=0, le=100)
email: str
class Config:
orm_mode = True
class GameBase(BaseModel):
id: int
name: str
class Config:
orm_mode = True
class UsersOut(UserBase):
games: List[GameBase]
class GamesOut(GameBase):
users: List[UserBase]
And I need to add entries by POST method, but I don't know how to do it exactly. I tried something like this:
#app.post('/connect/{uid}/{gid}')
def connect_to_game(uid: int, gid: int, db: Session = Depends(get_db)):
game = db.query(Game).filter(Game.id == gid).first()
user = db.query(User).filter(User.id == uid).first()
user_games = user(games=[game.id])
game_users = game(users=[user.id])
db.add_all([user_games, game_users])
db.commit()
return f'{game.name} successfully connected to {user.name}'
But it, certainly, doesn't work.
I tried to find information in pydantic and FastAPI documentations, but I couldn't. So I'll be really appreciated for any help or ideas.
I define models as:
game_users = Table('game_users', DBBase.metadata,
Column('game_id', ForeignKey('games.id'), primary_key=True),
Column('user_id', ForeignKey('users.id'), primary_key=True)
)
class Game(DBBase):
__tablename__ = 'games'
id = Column(Integer, primary_key=True)
name = Column(String(10), nullable=False)
users = relationship("User", secondary=game_users, backref='games')
class User(DBBase):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(10), nullable=False)
simplize back_populates by backref.
then assosicate objects:
>>> g1 = Game(name='g1')
>>> g2 = Game(name='g2')
>>> u1 = User(name='u1')
>>> u2 = User(name='u2')
>>> g1.users.extend([u1,u2])
>>> g2.users.extend([u1,u2])
>>> g1.users
[<models.User object at 0x105166b50>, <models.User object at 0x10519cfa0>]
>>> u1.games
[<models.Game object at 0x10512a280>, <models.Game object at 0x105166130>]
>>> s.add_all([g1,g2,u1,u2]) # s is db session
>>> s.commit()
So you just need to use the same type of adding relationships as above in your post method:
#app.post('/connect/{uid}/{gid}')
def connect_to_game(uid: int, gid: int, db: Session = Depends(get_db)):
game = db.query(Game).filter(Game.id == gid).first()
user = db.query(User).filter(User.id == uid).first()
game.users.append(user)
# no new instance, no need `add_all`
# db.add_all([user_games, game_users])
db.commit()
return f'{game.name} successfully connected to {user.name}'
Reference sqlalchemy many to many

One to one relation sqlalchemy

I am creating a TODO list. Each user has to have only one TODO list. ( I assume one to one model ).
If I set default value of todolist is None for each user, then create a todolist - it won't link it to the User. User.todolist will still be null. What should I do to have only one instance of todolist for each user?
My code:
class ToDoListBase(BaseModel):
items: List[ToDoItemCreate] = []
owner_id: int
class Config:
orm_mode = True
class UserBase(BaseModel):
todo: Optional[ToDoListCreate]
class Config:
orm_mode = True
Sqlalchemy models:
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
todolist = relationship('ToDoList', back_populates='owner', uselist=False)
class ToDoList(Base):
__tablename__ = 'todolists'
id = Column(Integer, primary_key=True, index=True)
owner_id = Column(Integer, ForeignKey('users.id'))
owner = relationship('User', back_populates='todolist')
What I expect to get is User where User.todolist = {items: [], owner_id: users.id}
what I get is User.todolist = null
and this is how I create todolist:
def get_or_create(self, owner_id: int, db: Session):
todolist = db.query(ToDoList).filter(ToDoList.owner_id==owner_id).first()
if not todolist:
todolist = ToDoList(
owner_id=owner_id,
)
db.add(todolist)
db.commit()
db.refresh(todolist)
return todolist

unhashable type: 'list' FastAPI PUT request

I am attempting to update an entry in my DB which should update the parent table projects as well as the child table rounds but I am getting this error 500:
sqlalchemy.exc.StatementError: (builtins.TypeError) unhashable type: 'list'
[SQL: UPDATE projects SET name = project_name=%(param_1)s, name=%(name)s, total_invested=%(total_invested)s, fee=%(fee)s, total_tokens=%(total_tokens)s, tge_date=%(tge_date)s WHERE projects.id = %(id_1)s]
[parameters: [{}]]
put request:
#router.put("/{id}")
def update_post(
id: int, updated_project: schemas.ProjectRound, db: Session = Depends(get_db)
):
project_query = db.query(models.Project).filter(models.Project.id == id)
project = project_query.first()
if project is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"project with id {id} not found",
)
project_query.update(updated_project.dict(), synchronize_session=False)
db.commit()
return project
schemas.py:
class Round(BaseModel):
round_name: str
token_price: float
vesting: str
class Config:
orm_mode = True
class ProjectBase(BaseModel):
name: str
total_invested: float
fee: int
total_tokens: int
tge_date: str
class ProjectRound(ProjectBase):
round: List[Round]
class Config:
orm_mode = True
models.py:
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String, nullable=False, unique=True)
total_invested = Column(Float, nullable=False)
fee = Column(Float, nullable=False)
total_tokens = Column(Integer, nullable=False)
tge_date = Column(String, nullable=False, server_default="TBC")
created_at = Column(
TIMESTAMP(timezone=True), nullable=False, server_default=text("now()")
)
round = relationship("Round", back_populates="projects", cascade="all,delete")
class Round(Base):
__tablename__ = "rounds"
id = Column(Integer, primary_key=True, nullable=False)
project_name = Column(
String, ForeignKey("projects.name", onupdate=("CASCADE"), ondelete=("CASCADE"))
)
round_name = Column(String, nullable=False)
token_price = Column(Float, nullable=False)
vesting = Column(String, nullable=False)
projects = relationship("Project", back_populates="round", cascade="all,delete")
I can seem to update the projects and rounds table. This is what I'm sending across from swagger:
{
"name": "project",
"total_invested": 0,
"fee": 0,
"total_tokens": 0,
"tge_date": "string",
"round": [
{
"round_name": "test",
"token_price": 0,
"vesting": "string"
},
{
"round_name": "test2",
"token_price": 0,
"vesting": "string"
}
]
}

Categories