peewee-async icon indicating copy to clipboard operation
peewee-async copied to clipboard

Invoking logic from model's .save() method

Open pahaz opened this issue 9 years ago • 5 comments

Hi! I have peewee model with custom save method:

        def save(self, *args, **kwargs):
            if not self.slug:
                self.slug = slugify(self.title.lower())
            return super().save(*args, **kwargs)

And If I call await self.manager.create(...) the save method will not call. It may little confuse.

pahaz avatar Nov 06 '16 06:11 pahaz

Yes, there's no way to call save() asynchronously. I agree it's not obvious and should be highlighted in docs. Thank you for the feedback!

rudyryk avatar Nov 11 '16 07:11 rudyryk

Not sure where I should put my save() auto validation/transformation code then... perhaps in a model's _transform_mutations() method, that is called by an overloaded insert() and update() ?

PS. @rudyryk thanks for making this awesome library! It was a pleasure to replace all threadpool executor calls in my codebase :)

gwillem avatar Dec 14 '16 14:12 gwillem

@gwillem Thank you :)

I think it's up to application code design. I prefer to leave that code in Manager subclasses and have some domain specific methods, so we can have an extra abstraction layer above models. That may be good for separation into multiple services in future.

But in fact, async code is usually more verbose for now and many design decisions still need to be made for better code.

Here's an example:

class PostManager(peewee_async.Manager):
    async def create_for_user(self, user, **attributes):
         """Save post by user."""
         # ...

    async def create_from_rss(self, **rss_data):
         """Save post imported from RSS."""
         # ...

rudyryk avatar Mar 05 '17 11:03 rudyryk

I use this, which has generic validation if a model has a validate method:

class ValidationManager(peewee_async.Manager):

    @asyncio.coroutine
    def update(self, obj, **kwargs):
        if hasattr(obj, 'validate'):
            obj.validate()
        return super().update(obj, **kwargs)

    @asyncio.coroutine
    def create(self, model_, **data):
        """WdG: overloaded, because we can run validate()
        """
        inst = model_(**data)

        if hasattr(inst, 'validate'):
            inst.validate()

        query = model_.insert(**dict(inst._data))

        pk = yield from self.execute(query)
        if pk is None:
            pk = inst._get_pk_value()
        inst._set_pk_value(pk)

        inst._prepare_instance()
        return inst

However, now I had to copy the create method. Hmm, I'd better pin my dependencies :D

gwillem avatar May 01 '17 07:05 gwillem

This is probably related to #96

rudyryk avatar Aug 05 '18 21:08 rudyryk