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
Add key-value to schema.Dict fails silently #393
Comments
Isn't that because using default of |
@vangheem still fails :( I thought that |
functionally, sure; however, if you think about just regular python, providing a dict as a default param is dangerous. For example, you should never do this:
You should do this instead:
That was my point. |
@vangheem yeah, I know, learned this the hard way in the past... hehe. |
Ahh, you're right. I forgot. |
Hey, I think I found the problem 160 async def update_default_dict(context, request):
161 context.images['new-key'] = 'value'
162 import pdb; pdb.set_trace()
163 -> request._txn.register(context)
164 assert len(context.images) == 0 # wat?
(Pdb) id(context.images)
140677027687088
(Pdb) id(context.images)
140677020557888
(Pdb) id(context.images)
140677027688240
(Pdb) id(context.images)
140677020557960
(Pdb) id(context.images)
140677020558032 |
(Replying your message I inspired myself) |
ahh right, that's a terrible side affect of the default value on Argh, not sure what the right answer is here. If we set the value here: https://github.com/plone/guillotina/blob/master/guillotina/content.py#L258 with say Then you won't be able to change the default value later if you've never modified the value. I know we've talked about this before and decided to leave current behavior. @masipcat for your case, you're better off leaving default as None and doing a code in your code if it is none and then setting it manually to \cc @bloodbare |
I also stumble on this in the past and the most reasonable solution I found was to provide a custom
This will make your default persist once it is looked up (it might be a write on read). |
@ale-rt yup, actually guillotina enforces not allowing writes on GET requests though. Also has the negative side affect of not being able to latently change a default value. |
@vangheem I can change my code as a temporary fix and ensure that this field is always set when created but IMHO the current behavior doesn't make sense for mutable objects. I'd suggest to:
|
I think I'm leaning toward |
|
I'm actually most in favor of the simplicity of option If we can convince @bloodbare that we're okay with Also, anyone have an opinion on what kind of version bump would be required for something like this? Depending on how we look at this as internal implementation vs part of the API affects if this would require major/minor/patch number... |
Here is my try to convince @bloodbare: I understand the Also, I understand that the current behavior makes sense for some cases. So I'd suggest something like this: class ...(Internface):
default_value = schema.Placeholder(
value={},
object=schema.Dict()
) Maybe the syntax doesn't make sense but the idea is to provide a mechanism to say explicitly "if no value is set to this field, return this value instead". |
the behavior of providing a default value in case of a null value seems a bit wired to me (at least sounds like unexpected behaviours.. nothing on the object.. but a value at runtime) I think I have had some issues with something like this on the past. Just my opinion is that if something is provided as default this has to be stored on the object.. (not transformed later at runtime) |
@vangheem not sure if I'm wrong.. but is possible that we fixed something like thia on the registry? |
@jordic I agree. @masipcat we do already have the "missing_value" functionality. We could just tweak @jordic @bloodbare what are your thoughts on ^^^ |
@vangheem I like this solution!! |
sounds good to me! |
@vangheem I don't understand why a setattr needs to happen when we do a getattr: On a ro operation (GET) getting always the default value or the default factorized value should be enough. In my opinion, the main value of default values are migrations and upgrades of the schema, so delaying setting the value of a field on the real object its a great feature. Also keeping the size of the db small is important, if you have 20M documents a simple default field serialized is a huge amount of disc space. On a rw operation (POST/PATCH) getting the default value or the default factorized value enables to assume that a list exists and just append to it, so it's important that in that case, we provide a mechanism that saves the recently created object. Cloud we make that if comes from defaultFactory we save on the object after getting on rw operations? If there is no defaultFactory we just return the default value (that should be used for immutable values) or missing_value. (We should also find how to not follow on that situation when we are serializing all the object as result of the operation doing a get to all fields and saving all the default values). Is likely what you said? R |
The problem here is about ergonomics. As an example.. you have an schema and you add a new field but you miss to evolve it throught a migration, you end up with something that exists but fails when you try to patch it.. because it doesn't exists (it exisits because you are getting the default)this feels a bit wired (because you end with inconsistent state due a performance optimitzation?) ... correct me if I'm wrong :) |
perhaps it's as easy as fail on boot saying that you have inconsitent schema changes.. or something like this.. but this case ahould fail explicit |
@jordic if you add a new field why you need to evolve it? A migration should only be needed if you are indexing it on ES, no? If you modify a field that exists from one type to another, you MUST do a migration If you modify the default value of a field and with the actual behavior you don't need to do anything. |
@bloodbare If that's the purpose of |
for the first case.. because it has a default that when you GET, it works.. but if you PATCH it doesn't exists on the instance.. (is what i think). for the second case it's something not explicit.. neither well documented and my thought on it is that it should be explicit and fail at least at startup. |
@masipcat I'm ok with having a field attribute that will set up its value or a factory to set the value (maybe should be a factory as this case mostly affects mutable objects). Should be on creation or on the attribute getter, agree. What I don't like is that, in any case, writing on the DB needs to be done on a GET operation. |
@bloodbare Can we prevent marking the object as dirty when the request method is get? Or check the method of the current request in the getattr to decide what to do . I don't know... |
No one is suggesting writing to db on GET request. Using setattr has
nothing to do with writing to db--it just ensures we get the same value
each time we do a getattr call. Right now, the fact that you get different
objects every time you do getattr is a terrible consequence IMO, and causes
a lot of confusion. This isn't the first time this has caused problems.
IMO, I don't think the potential data storage savings are worth the
consequences of this behavior.
…On Fri, Dec 21, 2018, 2:00 PM Jordi Masip ***@***.*** wrote:
What I don't like is that, in any case, writing on the DB needs to be done
on a GET operation.
@bloodbare <https://github.com/bloodbare> Can we prevent marking the
object as dirty when the request method is get? Or check the method of the
current request in the *getattr* to decide what to do . I don't know...
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#393 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAgAfWcmvfxmt-yDVQlFBLnrY0qyorPyks5u7T3ogaJpZM4ZeJFp>
.
|
I actually think simply doing a setattr when the default With any deserialization, we only ever do what is being deserialized. We won't be storing complete default values on content. On GET/serialization, we aren't saving the object. |
@vangheem So the fix would be just this line? masipcat@ec561f9 |
Yup, that should work. Regular "setattr(self, name,value)" works too! |
I'll change the line with |
I'm fine with it :) |
I'm also fine with it! Sorry to missunderstood that besides setattr we were going to do _p_register. R |
|
Hi! Here is my weekly issue/pr :P
I'm opening this issue because I found something weird with fields of type dict with default values (maybe list are affected as well)
Example
I have a custom content-type like this:
And I implemented an endpoint that adds a key-value pair to field
images
.After this endpoint retrieve the object and the field
images
is{}
.BUT if I replace the previous code with
context.images = {'new-key': 'value'}
then everything works fine.Is this a bug or I'm not using default value of field properly?
Reproduce
I implemented a test that reproduces the problem: masipcat@9be9d11
Thank you!
The text was updated successfully, but these errors were encountered: