Defining the Domain Model¶
The first change we'll make to our stock
pcreate-generated application will
be to define a domain model constructor representing a wiki page.
We'll do this inside our
Making Edits to
There is nothing special about the filename
project may have many models throughout its codebase in arbitrarily-named
files. Files implementing models often have
model in their filenames
(or they may live in a Python subpackage of your application package named
models) , but this is only by convention.
tutorial/tutorial/models.py file and edit it to look like the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
from sqlalchemy import ( Column, Integer, Text, ) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import ( scoped_session, sessionmaker, ) from zope.sqlalchemy import ZopeTransactionExtension DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) Base = declarative_base() class Page(Base): """ The SQLAlchemy declarative model class for a Page object. """ __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, unique=True) data = Column(Text)
(The highlighted lines are the ones that need to be changed.)
The first thing we've done is remove the stock
from the generated
models.py file. The
MyModel class is only a
sample and we're not going to use it.
Then, we added a
Page class. Because this is a SQLAlchemy application,
this class inherits from an instance of
1 2 3 4 5 6
class Page(Base): """ The SQLAlchemy declarative model class for a Page object. """ __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, unique=True) data = Column(Text)
As you can see, our
Page class has a class level attribute
__tablename__ which equals the string
'pages'. This means that
SQLAlchemy will store our wiki data in a SQL table named
Page class will also have class-level attributes named
data (all instances of
These will map to columns in the
id attribute will be the primary key in the table.
name attribute will be a text attribute, each value of
which needs to be unique within the column. The
data attribute is a text
attribute that will hold the body of each page.
We haven't looked at the details of this file yet, but within the
directory of your
tutorial package is a file named
in this file is executed whenever we run the
(as we did in the installation step of this tutorial).
Since we've changed our model, we need to make changes to our
script. In particular, we'll replace our import of
MyModel with one of
Page and we'll change the very end of the script to create a
rather than a
MyModel and add it to our
tutorial/tutorial/scripts/initializedb.py and edit it to look like the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import os import sys import transaction from sqlalchemy import engine_from_config from pyramid.paster import ( get_appsettings, setup_logging, ) from ..models import ( DBSession, Page, Base, ) def usage(argv): cmd = os.path.basename(argv) print('usage: %s <config_uri>\n' '(example: "%s development.ini")' % (cmd, cmd)) sys.exit(1) def main(argv=sys.argv): if len(argv) != 2: usage(argv) config_uri = argv setup_logging(config_uri) settings = get_appsettings(config_uri) engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.create_all(engine) with transaction.manager: model = Page(name='FrontPage', data='This is the front page') DBSession.add(model)
(Only the highlighted lines need to be changed.)
Installing the Project and re-initializing the Database¶
Because our model has changed, in order to reinitialize the database, we need
to rerun the
initialize_tutorial_db command to pick up the changes you've made
to both the models.py file and to the initializedb.py file.
See Initializing the Database for instructions.
Success will look something like this:
2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("pages") 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread] () 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread] CREATE TABLE pages ( id INTEGER NOT NULL, name TEXT, data TEXT, PRIMARY KEY (id), UNIQUE (name) ) 2011-11-27 01:22:45,278 INFO [sqlalchemy.engine.base.Engine][MainThread] () 2011-11-27 01:22:45,397 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT 2011-11-27 01:22:45,400 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit) 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO pages (name, data) VALUES (?, ?) 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread] ('FrontPage', 'This is the front page') 2011-11-27 01:22:45,402 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
Viewing the Application in a Browser¶
We can't. At this point, our system is in a "non-runnable" state; we'll 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 Starting the Application), you'll 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.