Time for action implementing picklists

What we need is a way to indicate that an entity attribute is a picklist. Run the following code (available as fruit.py) and point your browser to http://localhost:8080.

Chapter8/fruit.py

import os
import cherrypy
from entity import AbstractEntity, Attribute, Picklist
from browse import Browse
from display import Display
from logondb import LogonDB
db="/tmp/fruits.db"
class Entity(AbstractEntity):
	database = db
class Fruit(Entity):
	name = Attribute(displayname="Name")
	color = Attribute(displayname="Color",
			notnull = True,
			validate= Picklist([('Yellow',1),('Green',2),('Orange',0)]))
	taste = Attribute(displayname="Taste",
			notnull = True,
			validate= Picklist(Sweet=1,Sour=2))
class FruitBrowser(Browse):
	edit = Display(Fruit, edit=True)
	add = Display(Fruit, add=True)
current_dir = os.path.dirname(os.path.abspath(__file__))
cherrypy.quickstart(FruitBrowser(Fruit),config={
			'/':
			{ 'log.access_file' : os.path.join(current_dir,"access.
log"),
			'log.screen': False,
			'tools.sessions.on': True
			}
})

Click the Add button to create a new fruit instance. The color and taste attributes are defined as picklists, and clicking on the Color attribute, for example, may look like this:

Time for action implementing picklists

What just happened?

In the entity.py file, we added a Picklist class to store the available choices and their values:

Chapter8/entity.py

class Picklist:
	def __init__(self,list=None,**kw):
		self.list = collections.OrderedDict(list) if not list is 
None else collections.OrderedDict()
		self.list.update(kw)
	def __getitem__(self,key):
		return self.list[key]

The Picklist class is primarily a container for an OrderedDict (highlighted) and may be initialized either by a list or by passing any number of keywords to the __init__() method. However, the order of these keywords is not preserved, so even though we defined the color attribute of the fruit entity with this validate argument validate= Picklist(Yellow=1,Green=2,Orange=0), the order in the drop-down box was Orange, Green, and Yellow.

So although convenient, passing keywords makes the use of an OrderedDict rather pointless. Therefore, the __init__() method also accepts a list of tuples of key/value pairs and if present, uses this list to initialize the dictionary. Now if we would use validate= Picklist([('Yellow',1),('Green',2),('Orange',0)]), the order would be preserved, as shown in the following screenshot. It has the added benefit of allowing us to specify any string as a key and not just strings that are valid Python identifiers.

What just happened?

We already saw in the index() method of the Display class how to retrieve a list of possible choices. An Entity itself also needs to know how to deal with attributes that are picklists, for example, when it updates such an attribute. The __setattr__() method of the AbstractEntity class will have to be adapted as follows:

Chapter8/entity.py

def __setattr__(self,name,value):
		if name in self.validators :
			if type(self.validators[name])==Picklist:
				try:
					value=self.validators[name].list[value]
				except:
					# key not known, try value directly
					if not value in list(
				self.validators[name].list.values()):
							raise AttributeError(
		"assignment to "+name+" fails, "+
		str(value)+" not in picklist")
			elif not self.validators[name](value):
					raise AttributeError(
					"assignment to "+name+" does not validate")
	object.__setattr__(self,name,value)

The added lines (highlighted) check whether any validator is a Picklist, and if it is, tries to retrieve the value associated with the key. If this fails, it checks if the value that is entered is one of the values allowed. This way, it is valid to update a picklist attribute both with a key as well as a value. Given a fruit instance of the Fruit class defined earlier, the following lines are equivalent:

fruit.color = 'Green'
fruit.color = 2
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.206.254