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

Context is not present in vocabulary factory #31

Open
pysailor opened this issue Sep 24, 2014 · 9 comments · May be fixed by #70
Open

Context is not present in vocabulary factory #31

pysailor opened this issue Sep 24, 2014 · 9 comments · May be fixed by #70
Labels

Comments

@pysailor
Copy link

I have the following content type using a datagridfield. I want to use a dynamic vocabulary to compute values for a Choice field

class ITableRowSchema(form.Schema):
    attachment = schema.Choice(
        title=u"File (download)",
        source="local_files",
    )

class IMyContent(model.Schema):
    files = schema.List(
        title=u"Related files",
        value_type=DictRow(
            title=u"tablerow",
            schema=ITableRowSchema,),
    )
    form.widget(files=DataGridFieldFactory)

And the vocabulary factory:

@implementer(IVocabularyFactory)
class LocalFilesVocabulary(object):

    def __call__(self, context):
        ...

The problem is that context is NO_VALUE (<class 'z3c.form.interfaces.NO_VALUE'>), so I can't do creative things using my local context. If I put the same field directly into the my IMyContent schema, the context is the object on which the field gets called.

The answer to http://stackoverflow.com/questions/6623921/vocabulary-source-function-is-not-iterable-with-dexterity-in-plone-4-1 says: "I am not familiar enough with the datagrid widget setup to pinpoint where this goes wrong, but it appears that it generates widgets on-the-fly and I suspect it doesn't bind the fields for these correctly."
I spent some time in the debugger trying to find out where that might have to be done. I tried to be a smart-aleck with this hack:

def DataGridFieldFactory(field, request):
    """IFieldWidget factory for DataGridField."""
    bound = field.bind(request['PARENTS'][0])
    return FieldWidget(bound, DataGridField(request))

But still, the same result. And to quote Mikko from #2: "...does special things deep down with z3c.form. It's a place where nobody wants to go." Indeed!

Before I give this up as a lost case: did anybody already have the same issue and maybe found a solution for it?

@miohtama
Copy link
Contributor

No, no solution found for the last 4 years.

@miohtama
Copy link
Contributor

Also if not context: context = getSite() workaround has been sufficient.

Maybe digging up the objects from the field object in Python debugger revealed something. At least for other DGFs fields this gives nice results.

@pysailor
Copy link
Author

Ok, thanks for the info!

Unfortunately, getSite() is not sufficient in my case, because I really want to check for data that is on my local context.
If I find anything interesting, I'll write it here for posterity...

@simahawk
Copy link
Member

@pysailor hit the same problem... any outcome on this?

I'm trying to work around like this:

from zope.globalrequest import getRequest
req = getRequest()
context = req.PARENTS[0]

@djay
Copy link
Member

djay commented Nov 30, 2015

You can see its a issue with zope.schema itself.

in zope.schema._field

                    if IChoice.providedBy(attribute):
                        # Choice must be bound before validation otherwise
                        # IContextSourceBinder is not iterable in validation
                        bound = attribute.bind(value)
                        bound.validate(getattr(value, name))

@mtrebron
Copy link

mtrebron commented Jul 12, 2017

I just ran into this bug, trying to use a dynamic vocabulary in a dexterity object. The vocabulary content is based on the document it is called from. Works as intended when used like this:

    <field name="articles_list" type="zope.schema.Choice" lingua:independent="true">
      <description/>
      <required>False</required>
      <title>Articles List</title>
      <vocabulary>mdb_theme.ArticlesVocabulary</vocabulary>
    </field>

and fails like this:

    <field name="articles_list" type="zope.schema.List">
      <required>False</required>
      <description>Artikel Info</description>
      <title>Artikelliste</title>
      <value_type type="collective.z3cform.datagridfield.DictRow">
        <schema>mdb_theme.interfaces.IArticlesListRowSchema</schema>
      </value_type>
      <form:widget type="collective.z3cform.datagridfield.DataGridFieldFactory"/>
    </field>   

Thanks @simahawk for the hack, this will do for now!

@iham
Copy link

iham commented Jan 23, 2018

2018 and still the same problem.

the question is: WHY is there no context?
i cant answer that myself even after digging code for days.

can some (hard)core dev take a look to fix that?

wanting grids and fields with there context is not that exotic i guess.

@MrTango
Copy link

MrTango commented Apr 21, 2018

yes this is an anoying one, but with @simahawk workaround you can at least help yourself for the moment. I'm not so sure if I want to dive into z3c.form and datagridfield anytime soon ;).

I added this to my vocabulary and can use it now in both Situations:

from plone.dexterity.interfaces import IDexterityContent
from zope.globalrequest import getRequest
    
if not IDexterityContent.providedBy(context)::
    req = getRequest()
    context = req.PARENTS[0]

@quyet-nguyen quyet-nguyen linked a pull request Jun 11, 2018 that will close this issue
@fredvd
Copy link
Member

fredvd commented Jul 21, 2020

Two years later and I know I shouldn't have started to look into this, but here we are. I actually closed the proposed patch from #70 because I thought/read that #71 would be sufficient.

After a lot of pdb'ing, to answer @iham 's question why there is not context, it's happening in this part:

https://github.com/zopefoundation/z3c.form/blob/7b1f92e3b238d6bccdf9f4e6d2bf85522737cb07/src/z3c/form/field.py#L248-L262

the pull request #70 tried to be smart to set the context on the widgets before updateWidgets on the FieldWidgets is called. But the widgets are re-instantiated in the above section of code and then the widget.context is set to self.content, which is the NO VALUE

I'm too tired now to figure out with the FieldWidgets instance in the subform has this self.content set to NO VALUE, because that could lead to the newly instantiated widget getting the context.

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

Successfully merging a pull request may close this issue.

9 participants