Comments (5)
Yes, you are right.
I'm talking about the case, when I use the method from AsyncIOMotorCollection
and in the next version a method with the same name appears in Document or even in BaseModel, but with different behavior. I'll face an error or wrong logic after the update. It is impossible to mark this as deprecated because it is out of control.
from beanie.
I see what you mean now! You're right folks would be forced to update their code to reflect any Motor's of changes. That could end up being a pretty bad dev experience if they don't know where the method was changed.
Okay that answers my question. I'll use this with caution. 😅 Thanks again!
from beanie.
I'm leaving this here incase anyone else stumbles across it. I agree with the concerns that Roman has raised. I personally still wanted another way to quickly call Motor functions while taking Roman's feedback into consideration. I ended up with this:
from pydantic.main import ModelMetaclass
from motor.motor_asyncio import AsyncIOMotorCollection
from beanie import Document
class DocumentMetaClass(ModelMetaclass):
def __getattr__(cls, attr):
if attr.startswith('db_'):
motor_method = attr.split("db_")[1]
if callable(getattr(AsyncIOMotorCollection, motor_method, None)):
motor_collection = cls.get_motor_collection()
motor_func = classmethod(getattr(motor_collection, motor_method))
setattr(cls, attr, motor_func)
return getattr(cls, attr)
else:
raise AttributeError(f'{cls.__name__}.{attr}() cannot be found. To call a AsyncIOMotorCollection function try {cls.__name__}.db_{attr}() instead!')
class BaseDocument(Document, metaclass=DocumentMetaClass):
pass
class User(BaseDocument):
pass
By extending my BaseDocument class I'm able to explicitly call motor functions when they do not exist yet within Beanie.
$ User.count_documents({ 'username': username }, limit = 1)
~> AttributeError: User.count_documents() cannot be found. To call a AsyncIOMotorCollection function try User.db_count_documents() instead!
$ User.db_count_documents({ 'username': username }, limit = 1)
~> 1
I personally love Beanie for what it does. I like that it's a "micro" ODM. Therefore, I personally only want to rely on it for the components that are absolutely necessary. Everything else I'd like to default back to motor to ensure I can always use whatever is available from MongoDB. This solution helps me with that.
from beanie.
Hi Rodney,
Thank you for the feedback!
Yes, it looks good. Interesting feature.
Unfortunately, I see some potential problems with this approach. Right now Document
class has some methods with the same names, as the motor collection has, but with different interfaces and different outputs. And later I plan to add more (like count_documents()
from your example will appear in 4.0.0b1
soon. The problem is, in that case, it will override the dynamically attached method from the motor collection. This collision can be a problem if somebody already uses this motor method directly. Also, Document
itself is inherited from BaseModel
. Methods could be added and on the Pydantic side and on the Motor side then - the behavior is out of control in this case. I think the best strategy here would be to implement popular methods in Document
one by one with reasonable changes and keep others inside the motor collection.
What do you think about this? Does it make sense?
from beanie.
I hear what you're saying and you're right to be cautious!
To clarify: __getattr__
is only called when the method is unable to be located on your Document class, which like you mentioned includes BaseModel. So the order in which Python would look for an existing method on class User(Document)
would be..
- Defined on my User?
- Defined on Document?
- Defined on BaseModel?
- Defined on AsyncIOMotorCollection?
The first that matches gets called.
The part I do agree with is that it's a bit "magical". I'm just not sure I see or understand yet the value of recreating the Motor methods. I'll take a look at that beta branch.
from beanie.
Related Issues (20)
- [BUG] Multi-model pattern HOT 2
- [BUG] document class inherited from GenericModel with Link typed fields does not insert DBRef value after v1.21.0 HOT 1
- [need help][question]fields not define in Document with loss
- [BUG] Type hint error on pylance HOT 3
- Support `Binary.createFromBase64` Type HOT 1
- [BUG] `Document` constructor fails type check for instantiation with Mypy in `strict` mode
- [BUG] use_revision=True and use_cache=True result in RevisionIdWasChanged error HOT 2
- [BUG] `Link` type annotations don't play well with static type checkers (pylance, mypy) HOT 2
- [BUG] Got unknown type for Linked classes after 3nd level of Links. HOT 1
- [BUG] Weird `TypeError` when calling `init_beanie` using `dict` instead of `Dict` in module HOT 1
- [BUG] Document with UUID as Ids and Link/BackLink are badly fetched HOT 3
- [BUG] Validation fails in beanie 1.24.0 when dictionary key is an Enum HOT 1
- [BUG] RootModels with custom __iter__ methods break Beanie save() HOT 1
- [BUG] Fetching Links does not work if any aggregation is concatenated
- [BUG] RevisionIdWasChanged error when trying to update model
- [BUG] mypy strict no-untyped-call
- [BUG] UUIDs are not supported as ID types in Document.inspect_collection HOT 1
- [BUG] update_many with aggregate set fields to a nested document not the exact expression value HOT 1
- [BUG] FindQuery count() function does not use session parameter
- [BUG] Custom `beanie.BsonBinary` type doesn't work with pydantic 2.6.0+
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from beanie.