How do I implement polymorphic dataclass models with default values in the base model in SQLAlchemy 2.0 / Declarative? - sqlalchemy

I'm in the process of migrating to SQLAlchemy 2.0 and adopting new Declarative syntax with MappedAsDataclass. Previously, I've implemented joined table inheritance for my models. The (simplified) code looks like this:
from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, mapped_column
class Base(MappedAsDataclass, DeclarativeBase):
pass
class Foo(Base):
__tablename__ = "foo"
id: Mapped[int] = mapped_column(primary_key=True)
type: Mapped[str] = mapped_column(String(50))
foo_value: Mapped[float] = mapped_column(default=78)
__mapper_args__ = {"polymorphic_identity": "foo", "polymorphic_on": "type"}
class Bar(Foo):
__tablename__ = "bar"
id: Mapped[int] = mapped_column(ForeignKey("foo.id"), primary_key=True)
bar_value: Mapped[float]
__mapper_args__ = {"polymorphic_identity": "bar"}
The important bit for the question is the default value in foo_value. Because of its presence, a TypeError: non-default argument 'bar_value' follows default argument is raised. While moving fields around in the definition of a single class could make this error go away (but why is it raised in first place, since the field order is not really important?), it's not possible with inherited models.
How can I fix or work around this limitation? Am I missing something relevant from the documentation?

It seems I needed to use insert_default with MappedAsDataclass instead of default, as described in the docs.

Related

SQLAlchemy: get concrete class type of a relationship

I'm looking to get the class/type of a relationship in sqlalchemy.
class Parent(CustomBase):
children = relationship("Child")
class Child(Base):
pass
Is there a way to get the type of Parent.children (== Child) when you only have access to Parent?
(For context this is done from a CustomBase class, hence why I don't know what the relation type is beforehand)
You can get this information through Parent's mapper by following these steps:
import sqlalchemy as sa
parent_mapper = sa.inspect(Parent)
child_mapper = parent_mapper.relationships['children'].entity
child_entity = child_mapper.entity
print(child_entity)
Output:
<class '__main__.Child'>
This code is equivalent, but accesses Parent's mapper directly:
child_entity = Parent.__mapper__.relationships['children'].entity.entity

Simply format SQLAlchemy models returned by FastApi endpoint

Suppose I have a simple SQLAlchemy class and a simple Flask o FastAPI implementation like this:
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel
Base = declarative_base()
class A(Base):
__tablename__ = 'as'
my_id = Column(String)
class AModel(BaseModel):
myId:str = None
And a simple endpoint like this:
#app_router.get('/a')
def get_all_a(session:Session = Depends(get_session)):
return session.query(A).all()
How could I ensure that the returned list of this endpoint yields in camelCase like this:
[{'myId': 'id1'},{'myId': 'id2'}, ...]
Note: My application is rather complex, as I also have pagination implemented and some post-processings require a little bit more that just snake_case to camelCase conversion, so the simplest solution would be the best.
I've tried overriding dict() methods and similar stuff with no luck, simply cannot understand how FastAPI processes the results to obtain a JSON.
require a little bit more that just snake_case to camelCase conversion
Well, if you don't use response_model you don't have a lot of choices.
The solution is returning your dict with a conversion from snake_case to camelCase. You have functions that do it recursively.
Why it is the best solution ?
using regex it's super fast, faster than any lib that convert dict to obj like pydantic
If you definitely don't want to do this, well your only solution is using pydantic models, attrs or dataclasses and convert your db query output to one of those models type with camelCase variable name (dirty).
Since you are using fastapi you should use all the power of it.
I would suggest this:
from typing import List
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, Field
from pydantic import parse_obj_as
Base = declarative_base()
class A(Base):
__tablename__ = 'as'
my_id = Column(String)
class AModel(BaseModel):
myId: str = Field(alias="my_id", default=None)
#app_router.get('/a', response_model=List[AModel])
def get_all_a(session:Session = Depends(get_session)):
return parse_obj_as(List[AModel], session.query(A).all())
Keep in mind that having classes variables in CamelCase is not a good practice.
The gold answer would be to not return camel but snake and let your client do the work of conversion if needed.

Python Sqlalchemy Question - what is the class DicMixIn to Class Records?

I am very new to Python and SqlAlchemy. I stumbled upon this code while learning using SqlALchemy with Flask. Can you please help me to understand the class DictMixIn class - what are we doing here? Why are we using this?
class DictMixIn:
def to_dict(self):
return {
column.name: getattr(self, column.name)
if not isinstance(
getattr(self, column.name), (datetime.datetime, datetime.date)
)
else getattr(self, column.name).isoformat()
for column in self.__table__.columns
}
class Record(Base, DictMixIn):
__tablename__ = "Records"
id = Column(Integer, primary_key=True, index=True)
date = Column(Date)
country = Column(String, index=True)
cases = Column(Integer)
deaths = Column(Integer)
recoveries = Column(Integer)
At the end, the following snipped code was used - I believe they are using to_dict function above to print it. Am I right?
def show_records():
records = app.session.query(models.Record).all()
return jsonify([record.to_dict() for record in records])
The original code is here - https://github.com/edkrueger/sars-flask
I would really appreciate your help.
A mixin let's you add methods and properties to a class outside of the direct class hierarchy. You can then use the same mixin to inject methods/properties into many classes, ie. preventing duplication by not writing that same to_dict() into each database model. This mixin helps extend model classes in this case but this pattern is a python pattern and not specific to SQLAlchemy.
This specific mixin just lets you convert a database model instance into a simple dictionary. It seems that the intent as you pointed out is to jsonify a database model instance. JSON does not support Dates so that is why special care is taken to convert datetimes into a str with isoformat().
record.to_dict() might output something like:
{
"id": 100,
"date": "2021-09-11"
"country": "USA",
"cases": 100000000,
"deaths": 600000,
"recoveries": 95000000
}
mixin explained on stackoverflow
multiple inheritance in python docs -- the mixin pattern utilizes multiple inheritance in Python

Scala - Circe - Case Class Serialization without Class Name

I have used Circe previously for case class serialization / deserialization, and love how it can be used without the boilerplate code required by other Scala JSON libraries, but I'm running into an issue now I'm not sure how to resolve. I have an ADT (a sealed trait with several case class instances) that I would like to treat (from my Akka Http Service, using akka-http-json) generically (ie, return a List[Foo], where Foo is the trait-type), but when I do so using Circe's auto-deriviation (via Shapeless), it serializes the instances using the specific case class name as a 'discriminator' (eg, if my List[Foo] contains instances of Foo1, then each element in the resulting serialized list will have the key Foo1). I would like to eliminate the type name as a discriminator (ie, so that instead of having each element in the sequence prefixed with the type name-- eg, "Foo1": {"id : "1", name : "First",...}, I just want to serialize the case class instances to contain the fields of the case class: eg, {"id":"1,"name:"First",...}...Essentially, I'd like to eliminate the type name keys (I don't want the front-end to have to know what concrete case class each element belongs to on the back-end).All elements in the list to be serialized will be of the same concrete-type, all of which would be subtypes of my ADT (trait) type. I believe this can be done using Circe's semi-auto derivation, though I haven't had a chance to figure out exactly how. Basically, I would like to use as much of Circe's auto-derivation as possible, but eliminate outer-level class names from appearing in the resulting JSON. Any help / suggestions would be very much appreciated! Thanks!
you can do it following the instruction in the doc: https://circe.github.io/circe/codecs/adt.html
import cats.syntax.functor._
import io.circe.{ Decoder, Encoder }, io.circe.generic.auto._
import io.circe.syntax._
object GenericDerivation {
implicit val encodeEvent: Encoder[Event] = Encoder.instance {
case foo # Foo(_) => foo.asJson
case bar # Bar(_) => bar.asJson
case baz # Baz(_) => baz.asJson
case qux # Qux(_) => qux.asJson
}
implicit val decodeEvent: Decoder[Event] =
List[Decoder[Event]](
Decoder[Foo].widen,
Decoder[Bar].widen,
Decoder[Baz].widen,
Decoder[Qux].widen
).reduceLeft(_ or _)
}
import GenericDerivation._
import io.circe.parser.decode
decode[Event]("""{ "i": 1000 }""")
// res0: Either[io.circe.Error,Event] = Right(Foo(1000))
(Foo(100): Event).asJson.noSpaces
// res1: String = {"i":100}
This may not be the best answer, but after some more searching this is what I've been able to find. Instead of having the class name as a key in the Json produced, it can be serialized as a field as following:
implicit val genDevConfig: Configuration = Configuration.default.withDescriminator("type")
(you can use whatever field name here you'd like; Travis Brown's previous example for a similar issue used a field named what_am_i). So my apologies-- I do not yet know if there is a canonical or widely accepted solution to this problem, especially one that will easily work with Akka Http, using libraries such as akka-http-json, where I still seem to be encountering some issues, though I'm sure I'm probably overlooking something obvious! Anyway, my apologies for asking a question that seems to come up repeatedly!

Scala toJson when using net.liftweb.mongodb.record.MongoRecord and Argonaut

I'm scala newbie and come from a Ruby background so and am having trouble rendering json response in my web service for which I use scalatra, mongodb with liftweb mongo record and argonaut for JSon serialisation and deserialisation.
However based on the examples given at http://argonaut.io/ I'm unable to figure out how this would work when using the net.liftweb.mongo.record library.
On compiling this i get a error which says a type mismatch. The error description follows the code snippet.
package firstscalatraapp
import org.scalatra
import net.liftweb.mongodb._
import net.liftweb.mongodb.record.MongoRecord
import net.liftweb.mongodb.record.field.ObjectIdPk
import net.liftweb.record.field.StringField
import net.liftweb.record.field.IntField
import net.liftweb.record.field.PasswordField
import net.liftweb.record.field.DateTimeField
import net.liftweb.mongodb.record.MongoMetaRecord
import argonaut._
import Argonaut._
case class Person private extends MongoRecord[Person] with ObjectIdPk[Person] {
def meta = Person
object age extends IntField(this, 3)
object name extends StringField(this, 29)
object created_at extends DateTimeField(this)
object password extends PasswordField(this)
}
object Person extends Person with MongoMetaRecord[Person] {
implicit def PersonCodecJson: CodecJson[Person] =
casecodec3(Person.apply, Person.unapply)("name", "age", "things")
}
The Error i get is
[error] found : () => firstscalatraapp.Person
[error] required: (?, ?, ?) => ?
[error] casecodec3(Person.apply, Person.unapply)("name", "age", "things")
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
which seems logical because the constructor does not accept any parameters and the mongo library seems to be generating the val for the fields that i need for the class (I still don't fully understand what the lift mongo wrapper does yet).
So how do i define the implicit to be able to find serialise an object of type person.
Also how do I define serialisation capabilities when i'm dealing with collections. For instance when I have a List[Person].
Thanks in advance. I would really appreciate any help i can get on this.
I'm just about to start using Argonaut so I'm no expert on that but with that said your initial problem seems obvious.
casecodec3 needs a constructor and a deconstructor for the class you're defining the codec for. In the examples of Argonaut they're using case classes and these have automatically generated companion objects with apply/unapply for the fields defined. Which for casecodec3 needs to be 3. In your case, the case class is of zero-arity - you have no case class fields at all. The fields of the record are defined as inner objects with their own apply-methods (very imperative stuff). That's just the way lifts records are defined. So your apply method is just () => Person.
casecodec3 wants a function from a 3-tuple to Person and from Person to a 3-tuple. I would suggest skipping the case definition if you're going to use lift record. And create functions on the side instead. Something like:
object Person extends Person with MongoMetaRecord[Person] {
implicit def PersonCodecJson: CodecJson[Person] =
casecodec3(parse, serialize)("name", "age", "things")
// Something like
def parse(name: String, age: Int, things: Something) = {
val p = Person.createRecord
p.name(name)
...
}
def serialize(p: Person) = (p.name.get, p.age.get, p.things.get)
}
As for your other questions I think you can head back to argonaut.io again. Their documentation seems quite alright - maybe it was worse when you posted this question as it is kind of old?
I'm going to try to replace all my serialization from lift-json to argonaut right now so if you're still stuck (probably not) I might be able to answer better in a bit.