Get the item set as display - plone

I have a container x, with a Link item y set as display.
How can I access programmatically y if I know x?
I tried: getattr(x, 'default_page', None), but it returns None all the time.

By using getattr you may override plone default behavior regarding how to determinate the default page of an object (item or container).
Content objects in Plone inherit BrowserDefaultMixin, which provides the functionality of getting the default page of a object
The mixin, respectively a utility used by the mixin provides the desired method called getDefaultPage
>>> x = b.getObject()
>>> x.getDefaultPage()
...
This will return the right content object or view depending on the configuration on the object, on the FTI and on the View itself and more.
Have a look at get_default_page for more details.
And even better...
This canonical way of getting the default page, would also have helped finding the issue in your case pretty fast, since the method does certain checks to make sure the passed object provides the right "features". A string would not pass those checks.

default_page = getattr(x, 'default_page', None) is the answer. But make sure you have an object for x.
My mistake was I tried b.getObject().absolute_url() in my query instead of b.getObject().

Related

What would be the best method of creating a block which outputs a Redstone Signal

I'm wondering what would be the best way to allow a block to send out a specific amount of Redstone output conditionally. While looking through other blocks that gave a Redstone output, I noticed that they were mostly using the getWeakPower() method. However, I noticed that this was a Deprecated method and my IDE formats the method with a strikethrough. Additionally, I also found another method named getStrongPower() (also Deprecated). Which one of these two method would be best to override or would there be a better way to set the Redstone output of a block.
Although these blocks have the #Deprecated annotation to them, the JavaDoc comment states that "Implementing/overriding is fine". These getWeakPower() and getStrongPower() methods are only flagged as being deprecated in the net.minecraft.block.Block class because they are not meant to be accessed from the Block class, instead they are supposed to be accessed from the net.minecraft.block.BlockState class as that will contain the most up to date state of a given block instance.
It seems that most blocks which use Redstone functionality override the getWeakPower() method to control the Redstone output of the block by returning a specific value from 0 to 15 from the method. It’s also possible to separately control the output of each side (only output on one side or different outputs on each side), by using the Direction parameter passed into the method to determine the returned value.
Note: You must override the canProvidePower() method to return true. Otherwise, neighboring blocks will not check the block for a Redstone output and the desired functionality won’t work.

Can a plone.behavior be enabled for just some objects of a type?

I would like to set a marker interface to some objects that should have additional fields. If I remove this marker interface again the fields should be removed too.
Now I'm trying to understand plone.behavior. But I'm not sure if a behavior must be enabled for all objects of a type or is it possible to enable it for only a subset of objects of that type?
Take a look at collective.instancebehavior, an add-on aimed to do exactly what you want: to enable behaviors per content type instance.
Unfortunately I don't think there is a solution out of the box.
The simplest thing you can do is working on the form fields by overriding the updateFields method in the form.
This is untested demo code:
def updateFields(self):
if not IMyInterface.providedBy(self.context):
self.fields = (
self.fields.omit('IMyBehaviour.my_field')
)
As a reference have a look to:
https://github.com/plone/plone.app.users/search?utf8=%E2%9C%93&q=def+updateFields

Setting field defaults on programmatically created Dexterity items

I have a Dexterity content type based on plone.directives.form.Schema which has a number of form hints for assigning defaults:
#form.default_value(field=ITrial['start_on'])
def default_start_on(data):
return datetime.now()
Some of the defaults are more complex, passing back objects that are themselves instances of Dexterity types. These objects are essential for the main type's setup, which is triggered by various events.
I'm now in the process of testing. Ideally, I'd like to be able to use something like:
item = createContentInContainer(folder, 'ctcc.model.trial', 'item')
That is, I'd like the defaults to be picked up by the item without having to be manually passed into the constructor.
If I was using zope.schema I could use FieldProperty to set up proxies to the schema fields. Is there something equivalent for Dexterity, or perhaps a function for pushing an object through form creation?
Solution: I ended up going with David's option #1, intercepting ObjectCreatedEvent.
#grok.subscribe(ITrial, IObjectCreatedEvent)
def create_trial(trial, event):
if getattr(trial, 'start_on', None) is None:
trial.start_on = default_start_on(None)
It stills feels like I'm replicating part of form behaviour, but at least it's using the same functions that are providing the form defaults.
As you've discovered, the #form.default_value decorator is respected by z3c.form forms, but not when items are created in other ways. You have several options:
Write a handler for the ObjectCreatedEvent for your content type which sets up the necessary default values. This is the simplest approach to implement, but may not work if there are other handlers of this event that need the values in place.
Create your own subclass of Dexterity's generic Item class, and use it instead of Item as the basis for your content type. Then you can customize the __init__ method to set whatever you want. This would require migration of existing content items though, if you already have some.
This is a more complicated option. Replace the factory utility used to construct the content type. createContentInContainer ends up looking for an IFactory utility with a name equal to the factory attribute of the content type's FTI. The default implementation is in plone.dexterity.factory but you could replace it with a different one that does more.

Dealing with view implicit acquisition problems in Plone

In Plone adding a member variable in a view class instance automatically makes it a part of view acquisition chain. The problem is described in detail here:
http://collective-docs.readthedocs.org/en/latest/views/browserviews.html#views-and-automatic-member-variable-acquisition-wrapping
What is the suggested approach for dealing with this problem
Can we have Plone main template based views without implicit acquisition
How about viewlets and portlet renderers then?
If not... how one should deal with the problem so that self.xxx variables do not get extra acquisition wrapping?
Use Acquisition.aq_inner() to strip away the extra wrapping and restore the object to it's original path. Please, do not use the single-item list approach as described in the document you link to.
To show one example from the linked document, but corrected with aq_inner():
from Acquisition import aq_inner
self.obj = self.context.reference_catalog.lookupObject(value)
return aq_inner(self.obj).absolute_url() # Acquistion chain corrected
Alternatively, you can use the aq_inner attribute:
self.obj = self.context.reference_catalog.lookupObject(value)
return self.obj.aq_inner.absolute_url() # Acquistion chain corrected
but that only works on objects that inherit from Acquisition.Explicit or Acquisition.Implicit; the aq_inner() function returns the passed argument verbatim if it is not a Acquisition-wrapped object.

Accessing an object's workflow state in collective.easytemplate

I would like to use collective.easytemplate to generate templated emails (for content rules). However, I am not sure if it can output an objects workflow state. Anybody know if it is possible and how it is done?
Thanks.
You can, it is possible, and one way is to use the portal_workflow tool e.g. from parts/omelette/plone/app/contentrules/tests/test_action_workflow.py:
self.assertEquals('published',
self.portal.portal_workflow.getInfoFor(self.folder.d1, 'review_state'))
More generally, something like:
context.portal_workflow.getInfoFor(context, 'review_state')
in a page template should work. Or use the portal_catalog as Spanky suggests e.g. if "obj" is a catalog "brain" (i.e. part of a result set from a catalog search) then:
obj.review_state
should work.
The portal_catalog also has an index of the workflow's Review State, so if you don't already have the object you're working on (e.g. context ≠ the object) you could use the catalog, look up the object and get the review state from the resulting "brains" object.
Apparently there are ALSO browser view methods available to you as well, and I notice that one of them is workflow_state. See:
http://plone.org/documentation/manual/theme-reference/page/otherinfo

Resources