Have a look at the following code (available as crm1.py)
. It will define the entities identified in the previous section and the result, when run, will have a familiar look:
We've added a little bit of CSS styling to order the elements on the page, but in the final revision, we will give it a much more attractive look. Clicking on the Add new button will allow you to add a new entity.
These humble beginnings in implementing CRM were accomplished by the code in crm1.py:
Chapter8/crm1.py
import os
import cherrypy
from entity import AbstractEntity, Attribute, Picklist,
AbstractRelation
from browse import Browse
from display import Display
from editor import Editor
from logondb import LogonDB
db="/tmp/crm1.db"
class Entity(AbstractEntity):
database = db
class Relation(AbstractRelation):
database = db
class User(Entity):
name = Attribute(notnull=True, unique=True,
displayname="Name", primary=True)
class Account(Entity):
name = Attribute(notnull=True,
displayname="Name", primary=True)
class Contact(Entity):
firstname = Attribute(displayname="First Name")
lastname = Attribute(displayname="Last Name",
notnull=True, primary=True)
gender = Attribute(displayname="Gender",
notnull=True,
validate=Picklist(
Male=1,
Female=2,
Unknown=0))
telephone = Attribute(displayname="Telephone")
class Address(Entity):
address = Attribute(displayname="Address",
notnull=True, primary=True)
city = Attribute(displayname="City")
zipcode = Attribute(displayname="Zip")
country = Attribute(displayname="Country")
telephone = Attribute(displayname="Telephone")
class OwnerShip(Relation):
a = User
b = Account
class Contacts(Relation):
a = Account
b = Contact
class AccountAddress(Relation):
a = Account
b = Address
class ContactAddress(Relation):
a = Contact
b = Address
The first part is all about defining the entities and the relations between them according to the data model we sketched earlier. The concept is pretty much the same as for the books application, but for one important detail, the use of a picklist to limit the allowable choices for gender (highlighted). We will study these picklists in detail later in this chapter.
The next part creates the actual CherryPy application, with a Browse
page for each entity (highlighted):
Chapter8/crm1.py
logon = LogonDB() class AccountBrowser(Browse): display = Display(Account) edit = Display(Account, edit=True, logon=logon, columns=Account.columns+[Address,User]) add = Display(Account, add=True, logon=logon, columns=Account.columns+[Address,User]) class UserBrowser(Browse): display = Display(User) edit = Display(User, edit=True, logon=logon) add = Display(User, add=True, logon=logon) class ContactBrowser(Browse): display = Display(Contact) edit = Display(Contact, edit=True, logon=logon, columns=Contact. columns+[Account,Address]) add = Display(Contact, add=True, logon=logon, columns=Contact. columns+[Account,Address]) class AddressBrowser(Browse): display = Display(Address) edit = Display(Address, edit=True, logon=logon) add = Display(Address, add=True, logon=logon)
The final part defines a Root
class with an index()
method that will force the user to identify himself/herself first (highlighted) and will then redirect the user to the /entities page, served by the entities()
method.
This method will serve up a basepage with a navigation section that will allow the user to select a browse page for a type of entity and a content division which is initially empty, but will act as a container for either the chosen browse component or any edit or add page.
Chapter8/crm1.py
with open('basepage.html') as f:
basepage=f.read(-1)
class Root():
logon = logon
user = UserBrowser(User)
account = AccountBrowser(Account,
columns=Account.
columns+[User,Address,Contact])
contact = ContactBrowser(Contact,
columns=Contact.columns+[Address,Account])
address = AddressBrowser(Address)
@cherrypy.expose
def index(self):
return Root.logon.index(returnpage='../entities')
@cherrypy.expose
def entities(self):
username = self.logon.checkauth()
if username is None :
raise HTTPRedirect('.')
user=User.list(pattern=[('name',username)])
if len(user) < 1 :
User(name=username)
return basepage%'''
<div class="navigation">
<a href="user">Users</a>
<a href="http://account">Accounts</a>
<a href="contact">Contacts</a>
<a href="http://address">Addresses</a>
</div>
<div class="content">
</div>
<script>
... Javascript omitted ...
</script>
'''
cherrypy.config.update({'server.thread_pool':1})
cherrypy.engine.subscribe('start_thread',
lambda thread_index: Root.logon.connect())
current_dir = os.path.dirname(os.path.abspath(__file__))
cherrypy.quickstart(Root(),config={
'/':
{ 'log.access_file' :
os.path.join(current_dir,"access.log"),
'log.screen': False,
'tools.sessions.on': True
},
'/browse.js':
{ 'tools.staticfile.on':True,
'tools.staticfile.filename':current_dir+"/browse.js"
},
'/base.css':
{ 'tools.staticfile.on':True,
'tools.staticfile.filename':current_dir+"/base.css"
}
})
3.139.239.41