collective / collective.z3cform.datagridfield

Datagrid Field for z3c.forms
https://pypi.org/project/collective.z3cform.datagridfield/
8 stars 28 forks source link

Context is not present in vocabulary factory #31

Open pysailor opened 10 years ago

pysailor commented 10 years ago

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 commented 10 years ago

No, no solution found for the last 4 years.

miohtama commented 10 years ago

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 commented 10 years ago

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 commented 9 years ago

@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 commented 8 years ago

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 commented 7 years ago

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 commented 6 years ago

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 commented 6 years ago

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]
fredvd commented 4 years ago

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.