FastAPI 422 Unprocessable Entity - how to update many rows at once? - sqlalchemy

I want to update all rows in the values table that meet a condition based on a customer id and a group. I used the join statement to select all products that belong to the specific group. The table is set as
class Values(Base):
__tablename__ = 'values'
customer_id = Column(Integer, ForeignKey('customer.customer_id'), primary_key=True, ullable=False)
product_id = Column(Integer, ForeignKey('product.product_id'), primary_key = True, nullable= False)
quantity = Column(Numeric)
#router.put('/{customer_id}/{group}')
def update_values(customer_id: int, group:str, updated: schemas.Quantity, db: Session = Depends(get_db)):
sub_query = db.query(models.Values, models.Product.group).join(models.Product, models.Product.product_id == models.Values.product_id).filter(models.Values.customer_id==customer_id, models.Product.group==group).subquery()
main_query = db.query(models.Values).filter(models.Values.product_id.in_(sub_query))
main_query.update({models.Values.quantity: updated.item_value}, synchronize_session=False)
db.commit()
return main_query.all()
My schema is
class Quantity(BaseModel):
item_value: float
I get the error message 422 Unprocessable Entity.
{
"detail": [
{
"loc": [
"path",
"product_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
Could someone point out what I am doing wrong?

Related

How to add foreign key data in SQLALCHEMY_COMMIT_ON_TEARDOWN

in my model:
class User(db.Model):
__tablename__ = "user"
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(20))
class Product(db.Model):
__tablename__ = "product"
id = Column(Integer,primary_key=True,autoincrement=True)
name = Column(String(20))
userid = Column(ForeignKey("user.id"))
user = relationship("User",backref="product")
my flask run.py code:
...
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
...
#app.teardown_request
def dbsession_clean(excetion):
if app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"] :
if excetion is None:
try:
db.session.commit()
except:
db.session.rollback()
db.session.remove()
...
my view code
...
t = User(id=9,name="y9")
p = Product(id=5,name="p5",user=User.query.get(9))
db.session.add(t)
db.session.flush()
db.session.add(p)
...
the result is that data has saved in table, but only userid field is NULL int product table
how i solute it? please and thk

Sqlalchemy: Resolve cartesian product warning for many-to-many relationship with custom primaryjoin

Let's say I have the following database schema:
class A(Base):
__tablename__ = "a_table"
id = Column(Integer, primary_key=True, autoincrement=True)
version = Column(Integer, primary_key=True, default=1)
# More columns...
bs = relationship(
"B", secondary="a2b_table", back_populates="as"
)
class B(Base):
__tablename__ = "b_table"
id = Column(Integer, primary_key=True)
as = relationship(
A, secondary="a2b_table", back_populates="bs"
)
class A2B(Base):
__tablename__ = "a2b_table"
a_id = Column(
Integer(),
primary_key=True,
)
a_version = Column(
Integer,
primary_key=True,
)
b_id = sa.Column(
Integer,
ForeignKey("b.id", name="b_fk"),
primary_key=True,
)
__table_args__ = (
ForeignKeyConstraint(
[a_id, a_version],
[A.id, A.version],
name="a_fk",
),
{},
)
Each A is identified by an id and can have multiple versions. If something changes in the columns of A (the ones not shown), I produce a new A with the same id and version+1. The relationship bs gives me all instances of B that are associated with a specific version of an A.
The problem is, that the relationship as gives me all versions of each A that is associated with a specific B. Instead, I want the relationship to contain only the latest (highest) version of each A. Following the docs, I tried to solve this with a custom primaryjoin and a window function:
partition = select(
A,
row_number()
.over(order_by=A.version.desc(), partition_by=A.id)
.label("index"),
).alias()
partitioned_as = aliased(A, partition)
B.latest_as = relationship(
partitioned_as,
primaryjoin=and_(
partition.c.index == 1,
and_(
partitioned_as.id == A2B.a_id,
partitioned_as.version == A2B.a_version,
),
),
secondary="a2b_table",
viewonly=True,
)
Unfortunately, it doesn't work and I get the warning:
SELECT statement has a cartesian product between FROM element(s) "anon_1", "a2b_table" and FROM element "a_table". Apply join condition(s) between each element to resolve.
I checked the SQL statement sqlalchemy generates and it has anon_1, i.e. the query of partition, and a_table in its FROM clause. As far as I understand it, a_table shouldn't be in the FROM clause of this statement because it is already in the FROM clause of partition. I don't know how to get rid of it.
Could anyone point me in the right direction? Thanks in advance.

SqlAlchemy - make a query where Relationship Attribute is a list

I have two models:
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
...
stagesP_list = relationship(
'StageP',
back_populates='profiles_list',
secondary=stageP_profile
)
class Project(Base):
__tablename__ = 'projects'
id = Column(Integer, primary_key=True)
...
stagesP_list = relationship(
'StageP',
back_populates='projects_list',
secondary=stageP_project
)
I need to select Profiles for which at least one value of the Profile.stagesP_list is contained in the project.stagesP_list.
Please help to compose the query or indicate the direction in which to search.
If you have project instance loaded, you can compose the following query:
project = ...
stageP_ids = [obj.id for obj in project.stagesP_list]
query = session.query(Profile).filter(
Profile.stagesP_list.any(StageP.id.in_(stageP_ids))
)
You can also perform joins on the database directly from having only project_id:
query = (
session.query(Profile)
.join(StageP, Profile.stagesP_list)
.join(Project, StageP.projects_list)
.where(Project.id == project_id)
.distinct()
)

Fastapi sqlalchemy pydantic relational field

I am just a starter in FastAPI/Pydantic & SqlAlchemy - I have two model Post and Category where I want Post should fetch Category name instead of only id
when I try to use the below code it gives following error in console
Any help in solving this is much appreciated thank you!
response -> 1 -> category_name
field required (type=value_error.missing)
post.py models
class Post(Base):
__tablename__="post"
id = Column(Integer, primary_key=True, index=True)
title=Column(String(50))
user_id=Column(Integer, ForeignKey("users.id"))
category_id = Column(Integer, ForeignKey("category.id"))
category_name=relationship("Category", backref="post")
class Category(Base):
__tablename__="category"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
Pydantic models
class CategoryGet(BaseModel):
id:int
name:str
class Config:
orm_mode=True
class Post(BaseModel):
id = int
title=str
user_id=int
category_id = int
category_name=CategoryGet
class Config:
orm_mode=True
My mainapp.py
router = APIRouter()
#router.get("/", response_model=List[schemas.VehicleGet])
def get_vehicle(db: Session = Depends(get_db), skip: int = 0, limit: int = 50) -> Any:
vehicle = crud.post.get_multi(db, skip=skip, limit=limit)
return vehicle
Pydantic models attributes uses : instead of =
class Post(BaseModel):
id: int
title: str
user_id: int
category_id: int
category_name: CategoryGet
class Config:
orm_mode = True
I guess the problem is that, you forgot orm_mode=True config for you Post model and consequently it is unable to recognize the category_name field. I hope this will solve but if not you could check this thread where an example and some clarification about relationship handling with pydantic.

Django Model Design for Nested Json Output

I would like to design models in order to get json output as below. I've been trying different alternatives, using foreignkey or manytomany fields but couldn't get it worked.
This is what I want to get. Every user may have different trainings and each training for the subject user may have more than one date.
{
"userid": "12345",
"username": "John",
"trainings": {
"trn1": [
"20-01-2018"
],
"trn2": [
"20-01-2018",
"20-01-2019"
],
"trn3": [
"20-01-2018",
"20-01-2019",
"15-04-2019"
]
},
"notes": "a note about the user"
}
Depending on the database you are using. Postgres can utilize an ArrayField for storing the list of dates. If you are using any other DB you will need aditional model for dates or save them as a JSON list into a TextField. Here are both options:
With Postgres:
class User(models.Model):
userid = models.CharField()
username = models.CharField()
class Training(models.Model):
trainingid = models.CharField()
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='trainings',
)
dates = ArrayField(
models.DateField()
)
With other DBs:
class User(models.Model):
userid = models.CharField()
username = models.CharField()
class Training(models.Model):
trainingid = models.CharField()
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='trainings',
)
class Date(models.Model):
date = models.DateField()
training = models.ForeignKey(
Training,
on_delete=models.CASCADE,
related_name='dates',
)
Here is how to recreate your json object for any DB option:
users = []
for user in User.objects.all():
current_user = {
'userid': user.userid,
'username': user.username,
'trainings': {}
}
for training in user.trainings:
current_user['trainings'][training.trainingid] = []
for date in training.dates:
current_user['trainings'][training.trainingid].append(date.date)
users.append(current_user)
json_users = json.dumps(users)