Generate custom unique ids for new objects
portal_skins/plone_scripts/createObject.py is used to create objects when the user selects the relevant type in the
add new drop-down. This in turn calls the script
portal_skins/plone_scripts/generateUniqueId.py, which generates a unique default id (short name) for new objects based on the object's type, the current date and time, and a random number.
This generated id can be very long, upsetting the navtree (at least until Plone 2.1 comes along and fixes it) and making very unfriendly URLs. Also, in certain circumstances you may wish to have more control over the default id. For instance, in ArchPackage (in the Collective) we needed objects of the type
Improvement Proposal, which live exclusively inside an Improvement Proposal container (called
Roadmap), to have sequentially numbered ids, so that the first proposal had id 1, the second id 2 etc.
There are three general strategies you may employ.
First, if you are comfortable customising the site-wide generateUniqueId.py, you can do so in your
custom folder or a product's skin folder. This gets passed the parameter
type_name, which you can use to create type-specific naming schemes. However, you should be aware that if you are trying to create a re-usable product (and in general, you ought to do that anyway), this is a site-wide script used for all types in the site. Thus, another product may ovveride this script again, rendering your customisation ineffective. Another caveat is that you must ensure the id is unique, either by relying on random numbers like the current script does, or checking it explicitly against
context.objectIds () (or
context.keys() in Plone 4 or newer), which will return the currently used ids in the folder where the object is being created.
Second, if, like in the case of ArchPackage above, you want to custom-name a type which is only addable inside a container you control (that is,
Implicitly addable is turned off in
portal_types for the object, and the object is set in the list of allowed content types for some folderish container also part of your product, like the
Roadmap container above), you can let acquisition work its magic by defining a method like so on your container class:
security.declareProtected (ADD_CONTENTS_PERMISSION, 'generateUniqueId') def generateUniqueId (self, type_name): """Generate a unique ID for sub objects according to the following rules .... """ newId = "" ... # Set newId to something sensible - it must be # unique in the container! # You can use "if newId in self.objectIds ()" to test if # newId is already in use, or "if newId in self" in # Plone 4 or newer. return newId
ADD_CONTENTS_PERMISSION is assumed to be a constant containing the add contents permission for your product. Modify as necessary.
Third, it may be possible to use the
manage_afterAdd () hook in your class to rename an object after it has been created. This may be necessary if you need custom ids generated, possibly with the actual
id field hidden in your schema, and neither of the above two solutions will work (i.e. you can't customise the default script, and you don't control the parent container so you can't add a method to it). However, I have not seen any examples of this. Anyone with success stories or alternative suggestions, please leave a comment.