Skip to content
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

defaultFactory are not handled via applyChanges in zc3.form.form.py #32

Open
loechel opened this issue Oct 21, 2015 · 5 comments
Open
Labels

Comments

@loechel
Copy link
Member

loechel commented Oct 21, 2015

https://github.com/zopefoundation/z3c.form/blob/master/src/z3c/form/form.py#L46
tries to apply Changes on data if the have Changed, If you use a defaultFactory on a zope.schema field the value did not change, but also did not get written. This results in a side effect that if you try to resolve field value in a browser view the defaultFactory is executed again, and could provide a different result to different users.

easy solution always write defaultFactory Fields:
change

if util.changedField(field.field, newValue, context=content):

to

if util.changedField(field.field, newValue, context=content) or field.field.defaultFactory:
@projekt01
Copy link
Contributor

I do not understand your question. What do you mean with:
"if you try to resolve field value in a browser view the defaultFactory is executed again"

What do you mean with resolve field value?

@loechel
Copy link
Member Author

loechel commented Oct 22, 2015

I am sorry if my english is not good enough to explain the issue.

the value of a default factory is never written to the persitence layer, so browser views recalculate the expected value from the default factory.

Example:
User 1 has name foo which is provided to the form via a default factory. User 1 submit form, which is written into db

User 2 access a browser view of the data. As name was not written, the default factory recaluclates data, which if for the current user 2 bar.

so value should be foo for everybody, on every view. But it gets different values on every access.

@projekt01
Copy link
Contributor

The default value concept should work in z3c.form. What you are probably seeing could depend on the default attribute in zope.schema field. The z3c.schema field defines a missing_value and a default attribute. The z3c.form should be able to compare "field.default is not field.missing_value" and then use the default value if the given input is NO_VALUE. But this does not fit for dynamic values.

You can try to define a factory for the field.default aka defaultFactory. Something like:

def getRequest():
    interaction = zope.security.management.getInteraction()
    return interaction.participations[0]

def defaultUsernameFactory():
    request = getRequest()
    return request.annotations.get('username', '')

Then you can define a schema with a field like:

class IUser(zope.interface.Interface):
    username= zope.schemaChoice(
        title=u"Country"
        defaultFactory=defaultUsernameFactory
        )

Anf your form could look like:

class UserForm(Form):

    fields = fieldFields(interfaces.IUser).select('username')

    def update(self):
        # setup username
        self.request.annotations('username') = 'Fred'
        super(UserForm, self).update()

Does this make sense?

@idgserpro
Copy link

Another consequence of this is when we try to use the current date as default value of a date field:

def current_date():
    return datetime.date.today()

class IContent(model.Schema):
    date = schema.Date(
        title=_(u'Date'),
        required=True,
        defaultFactory=current_date,
    )

If I create content on 12/10/2018 and then try to access the date field on 12/11/2018, the returned value will be 12/11/2018 (current date) and not 12/10/2018. That is, it calls the current_date method again.

@idgserpro
Copy link

@projekt01 your proposal of #32 (comment) doesn't solve the problem of #32 (comment). @loechel's proposal makes more sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants