diff options
| author | Steve Piercy <web@stevepiercy.com> | 2015-11-12 00:46:11 -0800 |
|---|---|---|
| committer | Steve Piercy <web@stevepiercy.com> | 2015-11-12 00:46:11 -0800 |
| commit | 16a490fa4c44776d9a22b8a7ddc19a23702cb7ee (patch) | |
| tree | 2e2bcac026852f2e681955720a6bb53ee304efde /docs | |
| parent | 2aba031a8ef6fd7933b1d3f382303bc67a7c2acb (diff) | |
| parent | 0409cf178d4c0fa9a0d3b0858ab2294935b23609 (diff) | |
| download | pyramid-16a490fa4c44776d9a22b8a7ddc19a23702cb7ee.tar.gz pyramid-16a490fa4c44776d9a22b8a7ddc19a23702cb7ee.tar.bz2 pyramid-16a490fa4c44776d9a22b8a7ddc19a23702cb7ee.zip | |
Merge pull request #2112 from stevepiercy/feature/alchemy-scaffold-update
Finish work on basiclayout.rst and its src at wiki2/src/basiclayout/
Diffstat (limited to 'docs')
13 files changed, 243 insertions, 147 deletions
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst index 8a1dbf3f8..5d9b62eea 100644 --- a/docs/tutorials/wiki2/basiclayout.rst +++ b/docs/tutorials/wiki2/basiclayout.rst @@ -113,20 +113,22 @@ Finally ``main`` is finished configuring things, so it uses the :term:`WSGI` application: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 21 + :lines: 13 :language: py -View declarations via ``views.py`` ----------------------------------- + +View declarations via the ``views`` package +------------------------------------------- The main function of a web framework is mapping each URL pattern to code (a :term:`view callable`) that is executed when the requested URL matches the corresponding :term:`route`. Our application uses the :meth:`pyramid.view.view_config` decorator to perform this mapping. -Open ``tutorial/tutorial/views.py``. It should already contain the following: +Open ``tutorial/tutorial/views/default.py`` in the ``views`` package. It +should already contain the following: - .. literalinclude:: src/basiclayout/tutorial/views.py + .. literalinclude:: src/basiclayout/tutorial/views/default.py :linenos: :language: py @@ -135,13 +137,13 @@ function it decorates (``my_view``) with a :term:`view configuration`, consisting of: * a ``route_name`` (``home``) - * a ``renderer``, which is a template from the ``templates`` subdirectory - of the package. + * a ``renderer``, which is a template from the ``templates`` subdirectory of + the package. When the pattern associated with the ``home`` view is matched during a request, -``my_view()`` will be executed. ``my_view()`` returns a dictionary; the -renderer will use the ``templates/mytemplate.pt`` template to create a response -based on the values in the dictionary. +``my_view()`` will be executed. ``my_view()`` returns a dictionary; the +renderer will use the ``templates/mytemplate.jinja2`` template to create a +response based on the values in the dictionary. Note that ``my_view()`` accepts a single argument named ``request``. This is the standard call signature for a Pyramid :term:`view callable`. @@ -154,100 +156,105 @@ application. Without being processed by ``scan``, the decorator effectively does nothing. ``@view_config`` is inert without being detected via a :term:`scan`. -The sample ``my_view()`` created by the scaffold uses a ``try:`` and ``except:`` -clause to detect if there is a problem accessing the project database and -provide an alternate error response. That response will include the text -shown at the end of the file, which will be displayed in the browser to -inform the user about possible actions to take to solve the problem. +The sample ``my_view()`` created by the scaffold uses a ``try:`` and +``except:`` clause to detect if there is a problem accessing the project +database and provide an alternate error response. That response will include +the text shown at the end of the file, which will be displayed in the browser +to inform the user about possible actions to take to solve the problem. -Content Models with ``models.py`` ---------------------------------- +Content models with the ``models`` package +------------------------------------------ -.. START moved from Application configuration with ``__init__.py``. This - section is a WIP, and needs to be updated using the new models package. +In a SQLAlchemy-based application, a *model* object is an object composed by +querying the SQL database. The ``models`` package is where the ``alchemy`` +scaffold put the classes that implement our models. -The main function first creates a :term:`SQLAlchemy` database engine using -:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.`` prefixed -settings in the ``development.ini`` file's ``[app:main]`` section. -This will be a URI (something like ``sqlite://``): +First, open ``tutorial/tutorial/models/__init__.py``, which should already +contain the following: - .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 13 + .. literalinclude:: src/basiclayout/tutorial/models/__init__.py + :linenos: :language: py -``main`` then initializes our SQLAlchemy session object, passing it the -engine: +Our ``__init__.py`` will perform some imports to support later code, then calls +the function :func:`sqlalchemy.orm.configure_mappers`. - .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 14 +Next open ``tutorial/tutorial/models/meta.py``, which should already contain +the following: + + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :linenos: :language: py -``main`` subsequently initializes our SQLAlchemy declarative ``Base`` object, -assigning the engine we created to the ``bind`` attribute of it's -``metadata`` object. This allows table definitions done imperatively -(instead of declaratively, via a class statement) to work. We won't use any -such tables in our application, but if you add one later, long after you've -forgotten about this tutorial, you won't be left scratching your head when it -doesn't work. +``meta.py`` contains imports that are used to support later code. We create a +dictionary ``NAMING_CONVENTION`` as well. - .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 15 + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :end-before: metadata + :linenos: :language: py -.. END moved from Application configuration with ``__init__.py`` +Next we create a ``metadata`` object from the class +:class:`sqlalchemy.schema.MetaData`, using ``NAMING_CONVENTION`` as the value +for the ``naming_convention`` argument. We also need to create a declarative +``Base`` object to use as a base class for our model. Then our model classes +will inherit from the ``Base`` class so they can be associated with our +particular database connection. -In a SQLAlchemy-based application, a *model* object is an object composed by -querying the SQL database. The ``models.py`` file is where the ``alchemy`` -scaffold put the classes that implement our models. + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :lines: 15-16 + :lineno-start: 15 + :linenos: + :language: py -Open ``tutorial/tutorial/models.py``. It should already contain the following: +Next we define several functions, the first of which is ``includeme``, which +configures various database settings by calling subsequently defined functions. - .. literalinclude:: src/basiclayout/tutorial/models.py + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :pyobject: includeme :linenos: :language: py -Let's examine this in detail. First, we need some imports to support later code: +The function ``get_session`` registers a database session with a transaction +manager, and returns a ``dbsession`` object. With the transaction manager, our +application will automatically issue a transaction commit after every request +unless an exception is raised, in which case the transaction will be aborted. - .. literalinclude:: src/basiclayout/tutorial/models.py - :end-before: DBSession + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :pyobject: get_session :linenos: :language: py -Next we set up a SQLAlchemy ``DBSession`` object: +The ``get_engine`` function creates an :term:`SQLAlchemy` database engine using +:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.``-prefixed +settings in the ``development.ini`` file's ``[app:main]`` section, which is a +URI, something like ``sqlite://``. - .. literalinclude:: src/basiclayout/tutorial/models.py - :lines: 17 + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :pyobject: get_engine + :linenos: :language: py -``scoped_session`` and ``sessionmaker`` are standard SQLAlchemy helpers. -``scoped_session`` allows us to access our database connection globally. -``sessionmaker`` creates a database session object. We pass to -``sessionmaker`` the ``extension=ZopeTransactionExtension()`` extension -option in order to allow the system to automatically manage database -transactions. With ``ZopeTransactionExtension`` activated, our application -will automatically issue a transaction commit after every request unless an -exception is raised, in which case the transaction will be aborted. - -We also need to create a declarative ``Base`` object to use as a -base class for our model: +The function ``get_dbmaker`` accepts an :term:`SQLAlchemy` database engine, +and creates a database session object ``dbmaker`` from the :term:`SQLAlchemy` +class :class:`sqlalchemy.orm.session.sessionmaker`, which is then used for +creating a session with the database engine. - .. literalinclude:: src/basiclayout/tutorial/models.py - :lines: 17 + .. literalinclude:: src/basiclayout/tutorial/models/meta.py + :pyobject: get_dbmaker + :linenos: :language: py -Our model classes will inherit from this ``Base`` class so they can be -associated with our particular database connection. - -To give a simple example of a model class, we define one named ``MyModel``: +To give a simple example of a model class, we define one named ``MyModel``: - .. literalinclude:: src/basiclayout/tutorial/models.py + .. literalinclude:: src/basiclayout/tutorial/models/mymodel.py :pyobject: MyModel :linenos: :language: py Our example model does not require an ``__init__`` method because SQLAlchemy -supplies for us a default constructor if one is not already present, -which accepts keyword arguments of the same name as that of the mapped attributes. +supplies for us a default constructor if one is not already present, which +accepts keyword arguments of the same name as that of the mapped attributes. .. note:: Example usage of MyModel: diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py index 15e7e5923..eb771010f 100644 --- a/docs/tutorials/wiki2/src/basiclayout/setup.py +++ b/docs/tutorials/wiki2/src/basiclayout/setup.py @@ -10,7 +10,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'pyramid', - 'pyramid_chameleon', + 'pyramid_jinja2', 'pyramid_debugtoolbar', 'pyramid_tm', 'SQLAlchemy', diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py deleted file mode 100644 index 11ddccadb..000000000 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py +++ /dev/null @@ -1,27 +0,0 @@ -from sqlalchemy import ( - Column, - Integer, - Text, - Index, - ) - -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 MyModel(Base): - __tablename__ = 'models' - id = Column(Integer, primary_key=True) - name = Column(Text, unique=True) - value = Column(Integer) - -Index('my_index', MyModel.name, unique=True, mysql_length=255) diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py new file mode 100644 index 000000000..6ffc10a78 --- /dev/null +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py @@ -0,0 +1,7 @@ +from sqlalchemy.orm import configure_mappers +# import all models classes here for sqlalchemy mappers +# to pick up +from .mymodel import MyModel # flake8: noqa + +# run configure mappers to ensure we avoid any race conditions +configure_mappers() diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/meta.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/meta.py new file mode 100644 index 000000000..b72b45f9f --- /dev/null +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/meta.py @@ -0,0 +1,46 @@ +from sqlalchemy import engine_from_config +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from sqlalchemy.schema import MetaData +import zope.sqlalchemy + +NAMING_CONVENTION = { + "ix": 'ix_%(column_0_label)s', + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s" +} + +metadata = MetaData(naming_convention=NAMING_CONVENTION) +Base = declarative_base(metadata=metadata) + + +def includeme(config): + settings = config.get_settings() + dbmaker = get_dbmaker(get_engine(settings)) + + config.add_request_method( + lambda r: get_session(r.tm, dbmaker), + 'dbsession', + reify=True + ) + + config.include('pyramid_tm') + + +def get_session(transaction_manager, dbmaker): + dbsession = dbmaker() + zope.sqlalchemy.register(dbsession, + transaction_manager=transaction_manager) + return dbsession + + +def get_engine(settings, prefix='sqlalchemy.'): + return engine_from_config(settings, prefix) + + +def get_dbmaker(engine): + dbmaker = sessionmaker() + dbmaker.configure(bind=engine) + return dbmaker diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py new file mode 100644 index 000000000..5a2b5890c --- /dev/null +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py @@ -0,0 +1,17 @@ +from .meta import Base +from sqlalchemy import ( + Column, + Index, + Integer, + Text, +) + + +class MyModel(Base): + __tablename__ = 'models' + id = Column(Integer, primary_key=True) + name = Column(Text) + value = Column(Integer) + + +Index('my_index', MyModel.name, unique=True, mysql_length=255) diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/initializedb.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/initializedb.py index 66feb3008..f0d09729e 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/initializedb.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/initializedb.py @@ -2,36 +2,44 @@ import os import sys import transaction -from sqlalchemy import engine_from_config - from pyramid.paster import ( get_appsettings, setup_logging, ) -from ..models import ( - DBSession, - MyModel, +from pyramid.scripts.common import parse_vars + +from ..models.meta import ( Base, + get_session, + get_engine, + get_dbmaker, ) +from ..models.mymodel import MyModel def usage(argv): cmd = os.path.basename(argv[0]) - print('usage: %s <config_uri>\n' + print('usage: %s <config_uri> [var=value]\n' '(example: "%s development.ini")' % (cmd, cmd)) sys.exit(1) def main(argv=sys.argv): - if len(argv) != 2: + if len(argv) < 2: usage(argv) config_uri = argv[1] + options = parse_vars(argv[2:]) setup_logging(config_uri) - settings = get_appsettings(config_uri) - engine = engine_from_config(settings, 'sqlalchemy.') - DBSession.configure(bind=engine) + settings = get_appsettings(config_uri, options=options) + + engine = get_engine(settings) + dbmaker = get_dbmaker(engine) + + dbsession = get_session(transaction.manager, dbmaker) + Base.metadata.create_all(engine) + with transaction.manager: model = MyModel(name='one', value=1) - DBSession.add(model) + dbsession.add(model) diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/theme.min.css b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/theme.min.css index 2f924bcc5..0d25de5b6 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/theme.min.css +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/theme.min.css @@ -1 +1 @@ -@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a{color:#fff}.starter-template .links ul li a:hover{text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}}
\ No newline at end of file +@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a,a{color:#f2b7bd;text-decoration:underline}.starter-template .links ul li a:hover,a:hover{color:#fff;text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}} diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 index c9b0cec21..ff624c65b 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 @@ -1,12 +1,12 @@ <!DOCTYPE html> -<html lang="${request.locale_name}"> +<html lang="{{request.locale_name}}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="pyramid web application"> <meta name="author" content="Pylons Project"> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}"> + <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> <title>Alchemy Scaffold for The Pyramid Web Framework</title> @@ -14,7 +14,7 @@ <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this scaffold --> - <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet"> + <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> @@ -29,19 +29,19 @@ <div class="container"> <div class="row"> <div class="col-md-2"> - <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework"> + <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework"> </div> <div class="col-md-10"> - <div class="content"> - <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1> - <p class="lead">Welcome to <span class="font-normal">${project}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p> - </div> + {% block content %} + <p>No content</p> + {% endblock content %} </div> </div> <div class="row"> <div class="links"> <ul> - <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/">Docs</a></li> + <li class="current-version">Generated by v1.7.dev0</li> + <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li> diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2 new file mode 100644 index 000000000..bb622bf5a --- /dev/null +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2 @@ -0,0 +1,8 @@ +{% extends "layout.jinja2" %} + +{% block content %} +<div class="content"> + <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1> + <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework 1.7.dev0</span>.</p> +</div> +{% endblock content %} diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py index 57a775e0a..b947e3bb1 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py @@ -3,31 +3,63 @@ import transaction from pyramid import testing -from .models import DBSession +def dummy_request(dbsession): + return testing.DummyRequest(dbsession=dbsession) -class TestMyView(unittest.TestCase): + +class BaseTest(unittest.TestCase): def setUp(self): - self.config = testing.setUp() - from sqlalchemy import create_engine - engine = create_engine('sqlite://') - from .models import ( - Base, - MyModel, + self.config = testing.setUp(settings={ + 'sqlalchemy.url': 'sqlite:///:memory:' + }) + self.config.include('.models.meta') + settings = self.config.get_settings() + + from .models.meta import ( + get_session, + get_engine, + get_dbmaker, ) - DBSession.configure(bind=engine) - Base.metadata.create_all(engine) - with transaction.manager: - model = MyModel(name='one', value=55) - DBSession.add(model) + + self.engine = get_engine(settings) + dbmaker = get_dbmaker(self.engine) + + self.session = get_session(transaction.manager, dbmaker) + + def init_database(self): + from .models.meta import Base + Base.metadata.create_all(self.engine) def tearDown(self): - DBSession.remove() + from .models.meta import Base + testing.tearDown() + transaction.abort() + Base.metadata.create_all(self.engine) + + +class TestMyViewSuccessCondition(BaseTest): - def test_it(self): - from .views import my_view - request = testing.DummyRequest() - info = my_view(request) + def setUp(self): + super(TestMyViewSuccessCondition, self).setUp() + self.init_database() + + from .models.mymodel import MyModel + + model = MyModel(name='one', value=55) + self.session.add(model) + + def test_passing_view(self): + from .views.default import my_view + info = my_view(dummy_request(self.session)) self.assertEqual(info['one'].name, 'one') self.assertEqual(info['project'], 'tutorial') + + +class TestMyViewFailureCondition(BaseTest): + + def test_failing_view(self): + from .views.default import my_view + info = my_view(dummy_request(self.session)) + self.assertEqual(info.status_int, 500) diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/views/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/__init__.py diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py index 4cfcae4af..13ad8793c 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py @@ -3,26 +3,25 @@ from pyramid.view import view_config from sqlalchemy.exc import DBAPIError -from .models import ( - DBSession, - MyModel, - ) +from ..models.mymodel import MyModel -@view_config(route_name='home', renderer='templates/mytemplate.pt') +@view_config(route_name='home', renderer='../templates/mytemplate.jinja2') def my_view(request): try: - one = DBSession.query(MyModel).filter(MyModel.name == 'one').first() + query = request.dbsession.query(MyModel) + one = query.filter(MyModel.name == 'one').first() except DBAPIError: - return Response(conn_err_msg, content_type='text/plain', status_int=500) + return Response(db_err_msg, content_type='text/plain', status_int=500) return {'one': one, 'project': 'tutorial'} -conn_err_msg = """\ + +db_err_msg = """\ Pyramid is having a problem using your SQL database. The problem might be caused by one of the following things: 1. You may need to run the "initialize_tutorial_db" script - to initialize your database tables. Check your virtual + to initialize your database tables. Check your virtual environment's "bin" directory for this script and try to run it. 2. Your database server may not be running. Check that the @@ -32,4 +31,3 @@ might be caused by one of the following things: After you fix the problem, please restart the Pyramid application to try it again. """ - |
