emmett-framework / rest

REST extension for Emmett framework
BSD 3-Clause "New" or "Revised" License
14 stars 2 forks source link

update_values rules in models #22

Open josejachuf opened 10 months ago

josejachuf commented 10 months ago

Hi,

All the following happens to me using the latest versions of Emmett and Emmett Rest:

emmett 2.5.6 emmett-crypto 0.5.1 emmett-rest 1.5.2

All my models inherit from Signature

class TimeStamp(Model):
    created_at = Field('datetime')
    updated_at = Field('datetime')

    default_values = {
        'created_at': lambda: local_now(),
        'updated_at': lambda: local_now(),
    }

    update_values = {
        'updated_at': lambda: local_now(),
    }

class Signature(TimeStamp):
    refers_to(
        {'created_by': 'User'},
        {'updated_by': 'User'}
        )

    default_values = {
        'created_by': lambda: get_user(),
        'updated_by': lambda: get_user(),
    }

    update_values = {
        'updated_by': lambda: get_user(),
    }

What I am seeing that I have update a record from the API Rest, the updates are not worked, this is updated_at and updated_by maintain the value of when the record was created

josejachuf commented 10 months ago

Add some more information:

If I modify the record from the shell, the "updates_values" work, but it is through the API, no.

In the case I report I thought it could be that in the endpoint I use a custom update, but I tried it with another endpoint and follow the problem persists

from ... import Street
from .api import v1

streets = v1.rest_module(__name__,
                        name='api_streets',
                        model=Street,
                        url_prefix='streets',
                        # enabled_methods=['index', 'read'],
                        )
gi0baro commented 10 months ago

🤔 this sounds very confusing to me, as the update_values rules get applied in the ORM internals, regardless of where the instruction came from.

I think the only explanation here is that pyDAL is silently failing to compute the involved fields. You can easily verify this: check if any other field gets updated.

Also: if you have methods it is useless to use lambdas, you can just write 'updated_at': local_now for instance.

josejachuf commented 10 months ago

I think the only explanation here is that pyDAL is silently failing to compute the involved fields. You can easily verify this: check if any other field gets updated.

The image below corresponds to a PUT. It is seen that the nombre field was updated correctly, but update_at and update_by were not updated

imagen

josejachuf commented 10 months ago

In the PUT both functions (get_user and local_now) are called and both returning the correct values

josejachuf commented 10 months ago

writing it in this way it worked:

updated_at = Field.datetime(update=local_now)

in this way not:

update_values = {
     'updated_at': local_now,
}

But I don't know how to write it that way in the case of the updated_by which is a reference

class Signature(TimeStamp):
    refers_to(
        {'created_by': 'User'},
        {'updated_by': 'User'}
        )

    default_values = {
        'created_by': get_user,
        'updated_by': get_user,
    }

    update_values = {
        'updated_by': get_user,
    }
josejachuf commented 10 months ago

I did it this way and it works fine:

    @after_save
    def update_user_editor(self, row):
        row.update_record(updated_by=get_user)
        row.save(skip_callbacks=True)

Do you consider this solution correct?

gi0baro commented 10 months ago

@josejachuf I gonna run some tests locally, 'cause this is making me more and more confused.

Anyways, on the after_save theme I would probably prefer a before_save just to avoid the double update instruction.

josejachuf commented 10 months ago

Anyways, on the after_save theme I would probably prefer a before_save just to avoid the double update instruction.

Ok. Thanks!