[Grok-dev] object relationships
Martijn Faassen
faassen at startifact.com
Thu Jan 29 12:37:36 EST 2009
Hey,
Jeroen Michiel wrote:
> OK, I got it working!
Very cool!
> This is how I managed it:
>
> First of all, the IIntIds utility and a RelationCatalog need to be
> registered, so I made an event subscription to grok.IObjectAddedEvent to do
> this:
>
> @grok.subscribe(Test, grok.IObjectAddedEvent)
> def added(app, event):
> app['intids'] = intids = IntIds()
> grok.getSite().getSiteManager().registerUtility(intids,
> provided=IIntIds)
> app['catalog'] = catalog = relationfield.RelationCatalog()
> grok.getSite().getSiteManager().registerUtility(catalog,
> provided=ICatalog)
You can do these registrations with the local_utility() directive on the
application object. This is nicer as it integrates properly with the
rest of the configuration system of Grok. I believe I left hints in the
doctest of z3c.relationfield on how to do that.
> you also need an IObjectPath implementation, so I did this:
> class ObjectPath(grok.GlobalUtility):
> grok.provides(IObjectPath)
> def path(self, obj):
> return path(grok.getSite(), obj)
> def resolve(self, path):
> return resolve(grok.getSite(), path)
Yup. What's 'path' in this case? full Zope physical paths? That would
work or the z3c.objpath impelmentations will help. Perhaps you used
those looking at it, and that's good.
> Then I have some data I want to refer to:
> class IReferedData(Interface):
> name = schema.TextLine(title=u'The Name')
> class ReferedData(grok.Model):
> grok.implements(IReferedData, IHasIncomingRelations)
> def __init__(self, Name):
> self.name = Name
You could mix IHasIncomingRelations into the interface as well, but this
works just fine too.
> The the data that has a reference to ReferedData:
> class ITestData(Interface):
> rel = relationfield.Relation(title=u'Relation')
>
> class TestData(grok.Model):
> grok.implements(ITestData, HasOutgoingRelations)
Yup, looks good.
> and in my add form I do this:
> class Add(grok.AddForm):
> grok.context(Interface)
> form_fields = grok.Fields(ITestData,
> select=schema.Choice(title=u'Relation', source=TestSource())).omit('rel')
>
> @grok.action('Add')
> def Add(self, **data):
> testdata = TestData()
> intids = component.getUtility(IIntIds)
> id = intids.getId(data['select'])
> del data['select']
> self.applyData(testdata, **data)
> testdata.rel = relationfield.RelationValue(id)
> grok.getSite()['testdata'][str(len(grok.getSite()['testdata']))] =
> testdata
> self.redirect(self.url(testdata))
This is unfortunately a bit of a workaround, generating the other widget
and ignoring the widget for 'rel'. I need to look into making this work
properly so you don't have to do this.
> (the applyData is strictly not necessary, but will be if there would be
> other fields associated to ITestData)
>
> And that seems to do it! I can search relations and everything.
Awesome! I'm very impressed you got it figured out!
> Anyone who has any remarks about things I should have done differently
> perhaps, let me know, I can only learn from it.
Here you are. I sure hope you'll stick around on grok-dev and figure
more stuff out! Perhaps with my hints included you could turn it into a
document we can include on grok.zope.org?
Regards,
Martijn
More information about the Grok-dev
mailing list