Adding relations

One of the things we silently glossed over in the previous sections was the functionality to define relations between entities. Sure, the implementation of the Display class did allow for the creation of new instances, but we did not address how to define a relation, even though Display is already perfectly capable of showing columns that point to related entities like authors.

We could have hardcoded this behavior into specific implementations of Display like we did earlier when we implemented the first version of the books application, but this doesn't play well with the idea of creating components that can figure out those things for themselves, leaving the developer of the web application with fewer things to worry about.

The previous incarnation of the relation module was not quite up to this: we could define and administer a relation all right, but we'd have to do that by referring explicitly to an instance of a Relation class.

Because this isn't intuitive, we created a second version of the relation module that allows us to use the add() method inserted into the class definition of an Entity by the metaclass that creates a new relation. We do not have to care about the details: if we use add() to establish a relation between two entities, this is all taken care of.

This means that we can complete the add functionality of the Display class. For each column that refers to another entity (for example, the Author column of a book), we now implement some way for the user to make a choice, for example, with the autocomplete functionality, and process this choice in a rather simple manner: if it is empty, we do not add a relation, if it refers to a existing entity, add the relation and if not, create the related entity first before adding it.

We now have the functionality to refer to existing related items by their primary attribute or define a new one. However, for the end user, it might be very convenient to have auto completion on input fields that refer to related entities. This not only may save time, it also prevents inadvertently adding new entities when a typing error is made.

In previous chapters, we already encountered auto completion with the help of jQuery UI's autocomplete widget and we implemented the server-side functionality to retrieve lists of possible completions. All we have to do now is to make this functionality available in a manner that is independent from the actual related entity:

Chapter8/display.py

@cherrypy.expose
def autocomplete(self, entity, term, _=None):
	entity={c.__name__:c for c in self.columns
		if type(c)!=str}[entity]
	names=entity.getcolumnvalues(entity.primaryname)
	pat=compile(term,IGNORECASE)
	return json.dumps(list(takewhile(lambda x:pat.match(x),
				dropwhile(lambda x:not pat.match(x),names))))

The HTML and JavaScript that is generated by the index() method of the Display class will ensure that the preceding autocomplete() method will be called with the name of the entity of which we want to retrieve column values.

Any related class that the instance we are editing refers to is stored in the self.columns instance variable, just like the names of the regular attributes. The highlighted line, therefore, collects those column names that are actually classes and creates a dictionary indexed by name, which holds the corresponding classes as values.

When we use the name of the related entity passed to the autocomplete() method as the index, we will get hold of the class. This class is used in the next line to retrieve all column values for the column marked as the primary column. The final code to return a JSON encoded list of all those values that start with the term argument is the same as implemented earlier.

Note

Dictionary comprehensions are a new addition to Python 3.x, so it might be enlightening to write out the highlighted line in the example code in a more traditional manner:

classmap = {} 
for c in self.columns: 
	if type(c)!=str: 
			classmap[c.__name__] = c 
entity = classmap[entity]
..................Content has been hidden....................

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