tortoise / tortoise-orm

Familiar asyncio ORM for python, built with relations in mind
https://tortoise.github.io
Apache License 2.0
4.39k stars 357 forks source link

Auditing support #258

Open Nimond opened 4 years ago

Nimond commented 4 years ago

Is your feature request related to a problem? Please describe. I want to enable logs on create, update and delete.

Describe the solution you'd like Class methods which calls on create, update and delete.

grigi commented 4 years ago

Hi, are you specifically asking for logging hooks (e.g. callbacks) for SQL runtime statements, or better (more fine grained configurable) logging?

Nimond commented 4 years ago

I put it wrong. I don't need logs, only methods which calls on creating, deleting or changing.

...
class Team(Model):
    ...
    async def on_delete(self):
        logger.info(f'Team {self.id} deleted')
        ...
    async def on_update(self, changed_values):
        for name, values in changed_values.items():
            logger.info(f'Team {self.id} | {name}: {values[0]} -> {values[1]}')
        ...

I need this to understand which admin has changed something in db, but now I realized that I can’t pass the admin object for full logs to these callbacks. So, is it possible for the save function to return the dict of tuples of the changed fields (if some flag provided)?

diff = await user.save(diff=True)
# >>> diff
# {
#   'name': ('Melkor', 'Sauron'),
#   'item': ('Grond', 'Ring')
# }
grigi commented 4 years ago

Are you talking of signals? e.g: https://docs.djangoproject.com/en/3.0/ref/signals/#module-django.db.models.signals

grigi commented 4 years ago

Your goal is to keep a full diff-log of state?

:thinking: Using signals one could do a generic version of this that logs all changes, as long as the change is done via the ORM. But it could interfere with itself, and how to get old state? Would need to keep a copy of old state somewhere?

By using a mixin(or model subclass) that watches for local write operations, would then also keep a copy of old values, and then writes the log to some provided system might actually be a better solution. You would have to opt-in to it, and then any changes to that model would get sent to a declared callback.

Yes, an e.g. AuditedModel class that then has some defined callback that it would schedule as an async call that gets the changed state.

This is a good idea, and I'm happy to add this as a future feature.

Nimond commented 4 years ago

Thanks, I'll wait for the update.

grigi commented 4 years ago

I did say "future feature" meaning it will take a while for me to get to it. :disappointed: Probably months. If you need it sooner, I'll gladly accept a PR :grimacing: