I have a fastapi project using SQLModel that has JWT auth active. I have a registration endpoint and am trying to return a subset of the user record when a post to the registration endpoint is successful. I seem to be able to return the 'User' model which is tied to an actual table but I don't want to return the password hash so I created a new model called 'SensitiveUser' not tied to any table with the password removed. However, when I try to use this model and return the data from the endpoint I get the error "TypeError: 'SQLModelMetaclass' object is not iterable". Any insight on why this is happening is appreciated. I'm struggling to find this exact issue elsewhere online. Thanks.
Repo:
# Return all users.
def select_all_users():
with Session(rms_engine) as session:
statement = select(User)
res = session.exec(statement).all()
return res
# Returns a specific user record.
def find_user(name):
with Session(rms_engine) as session:
statement = select(User).where(User.username == name)
return session.exec(statement).first()
# Returns a specific user record withou password information.
def find_sensitive_user(name):
with Session(rms_engine) as session:
statement = select(SensitiveUser).where(SensitiveUser.username == name)
return session.exec(statement).first()
Models:
class User(SQLModel, table=True):
id: Optional[int] = Field(primary_key=True)
username: str
password: str = Field(max_length=256, min_length=6)
email: EmailStr
created_at: datetime.datetime = datetime.datetime.now()
is_admin: bool = False
class SensitiveUser(SQLModel):
id: int
username: str
email: str
created_at: datetime.datetime
The code below does work but returns more info than I want, namely the password:
@user_router.post('/register', status_code=201, tags=['users'], description='Register a new user')
def register(user: UserInput):
users = select_all_users()
if any(x.username == user.username for x in users):
raise HTTPException(status_code=400, detail='Username is taken')
hashed_pwd = auth_handler.get_password_hash(user.password)
u = User(username=user.username, password=hashed_pwd, email=user.email, is_admin=user.is_admin)
rms_session.add(u)
rms_session.commit()
stored_user = find_user(user.username)
return stored_user
The code below returns the "TypeError: 'SQLModelMetaclass' object is not iterable" error:
@user_router.post('/register', status_code=201, tags=['users'], description='Register a new user')
def register(user: UserInput):
users = select_all_users()
if any(x.username == user.username for x in users):
raise HTTPException(status_code=400, detail='Username is taken')
hashed_pwd = auth_handler.get_password_hash(user.password)
u = User(username=user.username, password=hashed_pwd, email=user.email, is_admin=user.is_admin)
rms_session.add(u)
rms_session.commit()
stored_user = find_sensitive_user(user.username) # <--- Error Occurs Here
return stored_user
JSONencoder needs to iterate over the object that you're returning (aSQLModelMetaclass), which causes the error. Try transforming the result into adict