-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create odmantic model from pydantic model #60
Comments
Unfortunately, this behavior is not currently not supported. A way around however would be to define the pydantic model from the odmantic one. As explained in the usage with pydantic section of the docs. |
@art049 from pydantic import BaseModel, Field
import odmantic
class Publisher(BaseModel):
name: str
founded: int = Field(ge=1440)
location: Optional[str] = None
class BookPublisher(Publisher):
address: str
employees: int = Field(ge=1)
class PublisherDB(odmantic.Model):
__base__ = Publisher
class BookPublisherDB(odmantic.Model):
__base__ = BookPublisher
and here changes to odmantic.model.ModelMetaclass.new: ...
def get_annotations(type_: type) -> dict:
"""Get type annotations of class hierarchy"""
d = {}
if issubclass(type_, pydantic.BaseModel) and type_ != pydantic.BaseModel:
for base in type_.__bases__:
d.update(get_annotations(base))
d.update(type_.__annotations__)
return d
class ModelMetaclass(BaseModelMetaclass):
@no_type_check
def __new__( # noqa C901
...
):
base = namespace.get('__base__')
if base:
namespace['__annotations__'] = get_annotations(base)
superclass
if namespace.get("__module__") != "odmantic.model" and namespace.get(
...
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
if base:
cls.__fields__.update(base.__fields__) # use original fields
cls.__pydantic_model__ = base
return cls I did some simple tests but there might be a million of cases that don't work |
Thanks @erny for the fix. Do you know if the annotations are still available in the odmantic models with this ? |
@art049 It's not a fix, but a hack (or tweak). Annotations should still be available. But I saw that the tests fail. I didn't do a complete checkout and run the tests locally. I replaced fields with the original pydantic ones, but it seems that your unit test don't like it. I'll try to work on this at another moment soon. Regards. |
Yes, the odmantic Field object are not actually inheriting from the pydantic ones. In the beginning I though it would help separating the concerns. But now i think it would actually be helpful to inherit from those directly. |
As a fan of Clean Architecture , I think this feature is essential. What's better is have another |
Maybe a naive question (I know almost nothing about odmantic internals) but would it be possible to make odmantic work directly with The only instance-level data I see in
|
I have to say in favour of the current implementation after using ODMantic that the Domain Object Model and the Persistence Object Model are different and that this forces us to separate cleanly both layers. While the Domain Object Model is used mainly in the Service Layer as input parameters and return values, the Persistence Object Model focuses on how to store and retrieve objects. Often they are different: most of the times the persistent objects have more attributes than the domain objects. But in basic CRUD, return values are often persistence model instances which are the same or very similar to the domain model instances. The service layer must translate domain objects to persistent objects and viceversa. I use I also put odmantic models (models.py) into another file as domain objects ( |
I think I understand the attraction in having both the pydantic model and the omdantic model, because it gives you more options as an odmantic developer (more things you can hook into). But maybe compare this to the example of an ORM that maps dictionaries to a database. If such an ORM works directly with a Python |
No worries @mnieber 😃 ; actually using the odmantic.Model class is necessary. The class itself is not the most important part but the metaclass is. The metaclass allows ODMantic to properly build the model object: provide the Proxy objects enabling filtering through python comparison operators, validating fields definition, providing substitution types for native BSON types to be handled.
Totally agree @erny , I faced as well the situation where it's needed to convert the odmantic instance to a dict and to parse it again into another pydantic model.
I didn't try it yet but it's probably possible to use the As we previously discussed and from the POC you showed @erny , creating ODMantic models from Pydantic models should be possible, in order to be able to pring all the desired functionalities: customize On top of this, since most of the time the domain objects are simply having fewer fields than the persistence layer objects (ODMantic models), I think that having a method to create pydantic submodels from an ODMantic model would be really helpful when architectures are smaller. I think this could be handled while working on "views" that would provide access to projected mongo documents (i.e. we only fetch a subset of the fields from documents stored in the database).
The partial updates will be made more simple soon by #39 which will add a new |
Hello everyone 👋. Thanks for tjr great work 🙏. Is there any improvement on this issue? I didn't try the code and read the entire conversation. It's 3 years old, so I wanted to ask. 🤓 |
@art049 Any progress? It's really useful expecially when there are existing Pydantic Models. |
I'm considering separating interface classes and persistence classes. Interface classes are the ones used in OpenAPI, i.e. in request / responses. Persistence classes are used when storing or retrieving objects from the store.
I would like to reuse pydantic models to create odmantic models, e.g. schemas.py (interface classes)
And in models.py (persistence classes):
Although the metaclass does it's work, it seems that something does go wrong, because:
The text was updated successfully, but these errors were encountered: