SQLAlchemy Class is not mapped - sqlalchemy

Im trying to update a user in FastAPI but i'm currently getting the error - Class 'api.schemas.instructor.Instructor' is not mapped
I've tried a couple of things to fix this like changing the schema and model but the results are either the error above or an error stating that the user already exists in the DB, is there anyway this can be resolved via the schema?
Heres my code;
Instructor schema
class Instructor(BaseModel):
id: str
full_name: str
phone_number: int
email: str
is_active: bool
is_superuser: bool
sex: str
car_type: str
area_covered: str
driving_school_name: str
driving_school_description: Optional[str] = None
adi_license: str
profile_image_one: Optional[str] = None
profile_image_two: Optional[str] = None
profile_image_three: Optional[str] = None
class Config:
orm_mode = True
Patch endpoint
#instructors.patch("/{user_id}")
def update(user_id: str, user: InstructorUpdate = Depends(InstructorUpdate.as_form), db: Session = Depends(d.get_db), profile_images: Optional[List[UploadFile]] = File(None)):
current_user = Instructor(**jsonable_encoder(crd.get_user(db, user_id)))
# current_user = jsonable_encoder(crd.get_user(db, user_id))
if current_user:
updated_user = crd.update_user(db, current_user, user, image_keys=image_keys)
return updated_user
else:
raise HTTPException(status_code=400, detail="User not found")
Update user function
def update_user(self, db: Session, db_obj: ModelType, usup: Any, image_keys: Optional[List[str]] = None):
obj_data = db_obj
if isinstance(usup, dict):
update_data = usup
else:
update_data = usup.dict(exclude_unset=True)
for field in obj_data:
if field in update_data:
if update_data[field] is not None:
setattr(db_obj, field, update_data[field])
# Todo - Error here "Class 'api.schemas.instructor.Instructor' is not mapped", need to fix this
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
Any help would be appreciated.

Related

SQLModel/SQLAlchemy updating parent is causing new children

I am using SQLModel to maintain a Region, which contain multiple areas.
These areas have in turn events through a many to many link table.
Creating my region with areas work fine, but if I update information in the region it duplicates all areas, all referencing the main region.
I am looking for a simplish way to make sure that if the region is the same, areas are the same and events on the areas are the same, the existing objects (and their ID's) are used.
This is my model:
class Region(SQLModel, table=True):
region_id: int = Field(primary_key=True)
name: str
description: Optional[str]
sourceAbbreviation: str
chapter: str
areas: Optional[List["Area"]] = Relationship(back_populates="region")
class AreaEvent(SQLModel, table=True):
area_id: int = Field(foreign_key="area.area_id", primary_key=True)
event_id: int = Field(foreign_key="event.event_id", primary_key=True)
class Area(SQLModel, table=True):
area_id: int = Field(primary_key=True)
name: str
description: Optional[str]
region_id: int = Field(foreign_key="region.region_id")
region: Optional["Region"] = Relationship(back_populates="areas")
events: Optional[List['Event']] = Relationship(back_populates="areas", link_model=AreaEvent)
class Event(SQLModel, table=True):
event_id: int = Field(primary_key=True)
name: str
areas: Optional[List[Area]] = Relationship(back_populates="events", link_model=AreaEvent)
And this is my retrieval method - nb: the get_adventureparts method returns a region with child areas.
#router.post("/region/{region_name}", response_model=RegionResponse)
async def add_region(
region_name: str,
sourceAbbreviation: str,
chapter: str,
session: Session = Depends(get_session)
):
db_region = session.query(Region).options(selectinload(Region.areas)).filter(Region.name == region_name.lower(),
Region.sourceAbbreviation == sourceAbbreviation.lower()).one_or_none()
if db_region is not None:
new_region = get_adventureparts(db_region)
for key, value in vars(new_region).items():
if key != "_sa_instance_state" and value is not None:
setattr(db_region, key, value)
session.commit()
region = session.query(Region).get(db_region.region_id)
else:
new_region = get_adventureparts(
Region(name=region_name.lower(), description="", sourceAbbreviation=sourceAbbreviation.lower(),
chapter=chapter))
session.add(new_region)
session.commit()
region = session.query(Region).get(new_region.region_id)
return RegionResponse.from_orm(region)

FastAPI / SQLAlchemy Create Multiple Users

I work a working API endpoint to create a single user.
#app.post("/entity/", response_model=List[schemas.User])
def create_user(user: schemas.User, db: Session = Depends(get_db)):
crud.create_user(db=db, user=user)
return JSONResponse(content={"message": "user created successfully"})
class User(BaseModel):
id: str = Field(default_factory=generate_id)
first_name: Optional[str] = ""
last_name: Optional[str] = ""
username: str
class Config:
orm_mode = True
def create_user(db: Session, user: schemas.User):
db_item = models.User(**user.dict())
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
This works, but I want to create multiple Users via one api request.
I guess the create_user function has to look somewhat like this:
def create_user(db: Session, data, user: schemas.User):
objects = []
for user in data:
db_item = models.User(**user.dict())
objects.append(dbitem)
db.bulk_save_objects(objects)
db.commit()
I just canĀ“t my head around what is the right way to create this kind of bulkinsert
You can accept a list of users as the request body.
def create_user(db: Session, users: List[schemas.User]):
objects = []
for user in users:
db_item = models.User(**user.dict())
objects.append(dbitem)
db.bulk_save_objects(objects)
db.commit()

Return function value as a value in a dictionary

dic1 = {}
class Piglet:
pass
def __init__(self,name,age):
self.name = name
self.age = age
def speak_or_not(self):
if self.age>2:
return True
else:
return False
def speak_dic(self):
global dic1
dic1[self.name] = speak_or_not()
pig1 = Piglet("Shaun",3)
pig1.speak_dic()
print(dic1)
I want to add the return value of the function speak_or_not as a value of dictionary dic1 which will result in a output like: {"Shaun":True} since age>2. But it prints an empty dictionary.
How to call a function and set the return value of the function as a value of the dictionary?
The code is not correct. In the speak_dic function, you are calling speak_or_not, which does not exist. Instead, you need to call self.speak_or_not.
Attaching the corrected code below.
dic1 = {}
class Piglet:
def __init__(self,name,age):
self.name = name
self.age = age
def speak_or_not(self):
if self.age>2:
return True
else:
return False
def speak_dic(self):
global dic1
dic1[self.name] = self.speak_or_not()
pig1 = Piglet("Shaun",3)
pig1.speak_dic()
print(pig1)
Also, you need to print dic1 to show the dictionary.
Hope this helps.

Play-Slick plugin, throws abstraction error in case of DateTime variables, data types

I have been using slick 2 as the dbms for my play app, though using play-slick plugin rather then slick independently, and added the tototoshi plugins as well, dependencies are:
"joda-time" % "joda-time" % "2.4"
"org.joda" % "joda-convert" % "1.6"
"com.github.tototoshi" %% "slick-joda-mapper" % "1.2.0"
"com.typesafe.play" %% "play-slick" % "0.6.1"
"com.typesafe.slick" %% "slick" % "2.0.3"
And the case class and projection are :
//Slick imports used
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick.DB
import scala.slick.lifted.ProvenShape
import com.github.tototoshi.slick.MySQLJodaSupport._
case class Design(
var id: Int,
var imageName: String,
var title: String,
var creatorID: Int,
var flagged: Boolean,
var modifiedTimestamp: Instant,
var createdTimestamp: Instant) {
def this() = this(0, "", "", 0, false, DateTime.now.toInstant, DateTime.now.toInstant)
}
class DesignProjection(tag: Tag) extends Table[Design](tag, "designs_47") {
def id: Column[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)
def imageName: Column[String] = column[String]("des_image_name")
def title: Column[String] = column[String]("des_title")
def creatorID: Column[Int] = column[Int]("des_creator_id")
def flagged: Column[Boolean] = column[Boolean]("des_flagged_link")
def modifiedTimestamp: Column[Instant] = column[Instant]("tt_modified_timestamp")
def createdTimestamp: Column[Instant] = column[Instant]("tt_tweeted_timestamp")
def * : ProvenShape[Design] = (id, imageName, title, creatorID, flagged, modifiedTimestamp, createdTimestamp) <> (
((Design.apply _): (Int, String, String, Int, Boolean, Instant, Instant) => Design).tupled,
Design.unapply)
}
And when I try to list all rows using method :
def list: List[Design] = {
println("Start Listing")
val result = DB.withSession { implicit session =>
val res = designProjection.list <-error here
res
}
convertListResultSet(result)
}
I get [RuntimeException: java.lang.AbstractMethodError], well I am more then sure its cause of the DataTime class, but I really don't know whats going wrong. I have used the tototoshi plugins as well. All other cases where DateTime are considered, they are working fine.
Any help or pointers are really welcome. Thank you
It is a known issue.
https://github.com/tototoshi/slick-joda-mapper/issues/19
Could you try slick-joda-mapper 1.1.0 ?

How to implement Slick + MySQL + SecureSocial?

How do I implement SecureSocial (newest snapshot version) plugin with Slick (1.0.1) and MySQL database?
I think that I have configured everything completely.
I have something like this in my User model class:
package models.auth
import securesocial.core._
import scala.slick.driver.MySQLDriver._
case class User(identityId: IdentityId,
firstName: String,
lastName: String,
fullName: String,
email: Option[String],
avatarUrl: Option[String],
authMethod: AuthenticationMethod,
oAuth1Info: Option[OAuth1Info] = None,
oAuth2Info: Option[OAuth2Info] = None,
passwordInfo: Option[PasswordInfo] = None) extends Identity
object User {
def apply(i: Identity): User = {
User(
i.identityId,
i.firstName,
i.lastName,
i.fullName,
i.email,
i.avatarUrl,
i.authMethod,
i.oAuth1Info,
i.oAuth2Info,
i.passwordInfo
)
}
}
object Users extends Table[User]("user") {
def userId = column[Long]("id", O.PrimaryKey, O.AutoInc)
def providerId = column[String]("providerId")
def email = column[Option[String]]("email")
def firstName = column[String]("firstName")
def lastName = column[String]("lastName")
def fullName = column[String]("fullName")
def avatarUrl = column[Option[String]]("avatarUrl")
def authMethod = column[AuthenticationMethod]("authMethod")
// oAuth 1
def token = column[Option[String]]("token")
def secret = column[Option[String]]("secret")
// oAuth 2
def accessToken = column[Option[String]]("accessToken")
def tokenType = column[Option[String]]("tokenType")
def expiresIn = column[Option[Int]]("expiresIn")
def refreshToken = column[Option[String]]("refreshToken")
// passwordInfo
def hasher = column[String]("hasher")
def password = column[String]("password")
def salt = column[String]("salt")
}
What do I have to do next? What imports to use and methods to implement?
Documentation is very poor.
You'll have to implement the UserService trait by extending the UserServicePlugin object.
The document is not that poor: UserService Documentation.
SecureSocial relies on an implementation of UserService to handle all the operations related to saving/finding users.