Defining the Domain Model¶
Let's make changes to our stock cookiecutter-generated application.
We will define two resource constructors, one representing a wiki page, and another representing the wiki as a mapping of wiki page names to page objects.
We will do this inside our
Because we are using ZODB to represent our resource tree, each of these resource constructors represents a domain model object.
We will call these constructors "model constructors".
Wiki constructors will be class objects.
A single instance of the "Wiki" class will serve as a container for "Page" objects, which will be instances of the "Page" class.
We will introduce a lot of concepts throughout the remainder of this tutorial. See also the chapter Resources for a complete description of resources and the chapter Traversal for the technical details of how traversal works in Pyramid.
Delete the database¶
In the next step, we will remove the
MyModel Python model class from our
Since this class is referred to within our persistent storage (represented on disk as a file named
Data.fs), we will have strange things happen the next time we want to visit the application in a browser.
Data.fs from the
tutorial directory before proceeding any further.
It is always fine to do this as long as you don't care about the content of the database.
The database itself will be recreated as necessary.
There is nothing special about the package name
A project may have many models throughout its codebase in arbitrarily named files and directories.
Files that implement models often have
model in their names, or they may live in a Python subpackage of your application package named
models, but this is only by convention.
tutorial/models/__init__.py file and edit it to look like the following:
1from persistent import Persistent 2from persistent.mapping import PersistentMapping 3 4 5class Wiki(PersistentMapping): 6 __name__ = None 7 __parent__ = None 8 9class Page(Persistent): 10 def __init__(self, data): 11 self.data = data 12 13def appmaker(zodb_root): 14 if 'app_root' not in zodb_root: 15 app_root = Wiki() 16 frontpage = Page('This is the front page') 17 app_root['FrontPage'] = frontpage 18 frontpage.__name__ = 'FrontPage' 19 frontpage.__parent__ = app_root 20 zodb_root['app_root'] = app_root 21 return zodb_root['app_root']
The emphasized lines indicate changes, described as follows.
MyModel class from the generated
MyModel class is only a sample and we're not going to use it.
Next we add an import at the top for the
We will use this for a new
Page class in a moment.
1from persistent import Persistent 2from persistent.mapping import PersistentMapping
Then we add a
5class Wiki(PersistentMapping): 6 __name__ = None 7 __parent__ = None
We want it to inherit from the
persistent.mapping.PersistentMapping class because it provides mapping behavior.
It also makes sure that our
Wiki page is stored as a "first-class" persistent object in our ZODB database.
Wiki class should have two attributes set to
None at class scope:
If a model has a
__parent__ attribute of
None in a traversal-based Pyramid application, it means that it is the root model.
__name__ of the root model is also always
Now we add a
9class Page(Persistent): 10 def __init__(self, data): 11 self.data = data
This class should inherit from the
We will give it an
__init__ method that accepts a single parameter named
This parameter will contain the reStructuredText body representing the wiki page content.
Page objects don't have an initial
All objects in a traversal graph must have a
__name__ and a
We do not specify these here.
__parent__ will be set by a view function when a
Page is added to our
We will create this function in the next chapter.
As a last step, edit the
13def appmaker(zodb_root): 14 if 'app_root' not in zodb_root: 15 app_root = Wiki() 16 frontpage = Page('This is the front page') 17 app_root['FrontPage'] = frontpage 18 frontpage.__name__ = 'FrontPage' 19 frontpage.__parent__ = app_root 20 zodb_root['app_root'] = app_root 21 return zodb_root['app_root']
View the application in a browser¶
We cannot. At this point, our system is in a "non-runnable" state We will need to change view-related files in the next chapter to be able to start the application successfully. If you try to start the application (See Start the application), you will wind up with a Python traceback on your console that ends with this exception:
ImportError: cannot import name MyModel
This will also happen if you attempt to run the tests.