Changeset 5756

Show
Ignore:
Timestamp:
11/24/08 03:05:45 (2 months ago)
Author:
carndt
Message:

Implement #2013 (add database bootstrap command to quickstart templates)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.1/turbogears/qstemplates/quickstart/+package+/commands.py_tmpl

    r5490 r5756  
    11# -*- coding: utf-8 -*- 
    2 """This module contains functions called from console script entry points.""" 
     2"""This module contains functions to be called from console script entry points. 
     3""" 
    34 
    45import sys 
     6import optparse 
     7 
    58from os import getcwd 
    69from os.path import dirname, exists, join 
     
    3740import turbogears 
    3841 
     42from ${package}.release import version 
     43 
     44 
    3945cherrypy.lowercase_api = True 
    4046 
     
    4450 
    4551 
    46 def start(): 
    47     """Start the CherryPy application server.""" 
     52def _read_config(args): 
     53    """Read deployment configuration file. 
    4854 
     55    First looks on the command line for a desired config file, if it's not on 
     56    the command line, then looks for 'setup.py' in the parent of the directory 
     57    where this module is located. 
     58 
     59    If 'setup.py' is there, assumes that the application is started from 
     60    the project directory and should run in development mode and so loads the 
     61    configuration from a file called 'dev.cfg' in the current directory. 
     62 
     63    If 'setup.py' is not there, the project is probably installed and the code 
     64    looks first for a file called 'prod.cfg' in the current directory and, if 
     65    this isn't found either, for a default config file called 'default.cfg' 
     66    packaged in the egg. 
     67 
     68    """ 
    4969    setupdir = dirname(dirname(__file__)) 
    5070    curdir = getcwd() 
    5171 
    52     # First look on the command line for a desired config file, 
    53     # if it's not on the command line, then look for 'setup.py' 
    54     # in the current directory. If there, load configuration 
    55     # from a file called 'dev.cfg'. If it's not there, the project 
    56     # is probably installed and we'll look first for a file called 
    57     # 'prod.cfg' in the current directory and then for a default 
    58     # config file called 'default.cfg' packaged in the egg. 
    59     if len(sys.argv) > 1: 
    60         configfile = sys.argv[1] 
     72    if args: 
     73        configfile = args[0] 
    6174    elif exists(join(setupdir, "setup.py")): 
    6275        configfile = join(setupdir, "dev.cfg") 
     
    6679        try: 
    6780            configfile = pkg_resources.resource_filename( 
    68               pkg_resources.Requirement.parse("${project}"), 
     81              pkg_resources.Requirement.parse("${package}"), 
    6982                "config/default.cfg") 
    7083        except pkg_resources.DistributionNotFound: 
    71             raise ConfigurationError("Could not find a configuration file.") 
     84            raise ConfigurationError("Could not find default configuration.") 
    7285 
    7386    turbogears.update_config(configfile=configfile, 
    7487        modulename="${package}.config") 
    7588 
     89def bootstrap(): 
     90    """Example function for loading bootstrap data into the database 
     91 
     92    You can adapt this to your needs to e.g. accept more options or to 
     93    run more functions for bootstrapping other parts of your application. 
     94    By default this runs the function '${package}.model.bootstrap_model', which 
     95    creates all database tables and optionally adds a user. 
     96 
     97    The following line in your project's 'setup.py' file takes care of 
     98    installing a command line script when you install your application via 
     99    easy_install which will run this function: 
     100 
     101        'bootstrap-${package} = ${package}.commands:bootstrap', 
     102 
     103    """ 
     104 
     105    optparser = optparse.OptionParser(usage="%prog [options] [config-file]", 
     106        description="Load bootstrap data into the database defined in " 
     107        "config-file.", version="${project} %s" % version) 
     108    optparser.add_option('-C', '--clean', dest="clean", action="store_true", 
     109        help="Purge all data in the database before loading the bootrap data.") 
     110    optparser.add_option('-u', '--user', dest="user", metavar="USERNAME", 
     111        help="Create a default user USERNAME (prompts for password).") 
     112    options, args = optparser.parse_args() 
     113    if options.user: 
     114        options.user = options.user.decode(sys.getfilesystemencoding()) 
     115    _read_config(args) 
     116    from ${package}.model import bootstrap_model 
     117    bootstrap_model(options.clean, options.user) 
     118 
     119def start(): 
     120    """Start the CherryPy application server.""" 
     121 
     122    _read_config(sys.argv[1:]) 
    76123    from ${package}.controllers import Root 
    77  
    78124    turbogears.start_server(Root()) 
  • branches/1.1/turbogears/qstemplates/quickstart/+package+/model.py_tmpl

    r5736 r5756  
     1import sys 
     2 
    13#if $identity != 'none' 
    24from datetime import datetime 
    35#end if 
    46 
     7import pkg_resources 
    58#if $sqlobject == 'True' 
    6 import pkg_resources 
    79pkg_resources.require("$sqlobjectversion") 
    810#elif $sqlalchemy == 'True' 
    9 import pkg_resources 
    1011pkg_resources.require("$sqlalchemyversion") 
    1112#if $elixir == 'True' 
     
    1920# (see http://www.sqlobject.org/SQLObject.html#declaring-the-class) 
    2021from sqlobject import SQLObject, SQLObjectNotFound, RelatedJoin 
     22from sqlobject.inheritance import InheritableSQLObject 
    2123# import some datatypes for table columns from SQLObject 
    2224# (see http://www.sqlobject.org/SQLObject.html#column-types for more) 
     
    3234# (see http://www.sqlalchemy.org/docs/04/types.html for more) 
    3335from elixir import String, Unicode, Integer, DateTime 
     36from turbogears.database import get_engine, metadata, session 
    3437#else 
    35 from turbogears.database import mapper, metadata, session 
     38from turbogears.database import get_engine, mapper, metadata, session 
    3639# import some basic SQLAlchemy classes for declaring the data model 
    3740# (see http://www.sqlalchemy.org/docs/04/ormtutorial.html) 
     
    467470#end if 
    468471#end if 
     472 
     473# functions for populating the database 
     474 
     475def bootstrap_model(clean=False, user=None): 
     476    """Create all database tables and fill them with default data. 
     477 
     478    This function is run by the 'bootstrap' function from the commands module. 
     479    By default is calls two functions to create all database tables for your 
     480    model and optionally create a user. 
     481 
     482    You can add more functions as you like to add more boostrap data to the 
     483    database or enhance the functions below. 
     484 
     485    If 'clean' is True, all tables defined by you model will dropped before 
     486    creating them again. If 'user' is not None, 'create_user' will be called 
     487    with the given username. 
     488 
     489    """ 
     490    create_tables(clean) 
     491    if user: 
     492        create_default_user(user) 
     493 
     494def create_tables(drop_all=False): 
     495    """Create all tables defined in the model in the database. 
     496 
     497    Optionally drop existing tables before creating them. 
     498 
     499    """ 
     500#if $identity == 'sqlobject' 
     501    ## XXX: This is duplicated from testutil.DBTestSO and should be factored 
     502    ## out to a reusable function (maybe into turbogears.database?). 
     503    from turbogears.util import get_model 
     504    from inspect import isclass 
     505 
     506    model = get_model() 
     507    if not model: 
     508        from ${package}.commands import ConfigurationError 
     509        raise ConfigurationError( 
     510            "Unable to create database tables without a model") 
     511 
     512    try: 
     513        so_classes = [model.__dict__[x] for x in model.soClasses] 
     514    except AttributeError: 
     515        so_classes = model.__dict__.values() 
     516 
     517    if drop_all: 
     518        print "Dropping all database tables defined in model." 
     519        for item in reversed(so_classes): 
     520            if isclass(item) and issubclass(item, SQLObject) and \ 
     521                    item is not SQLObject and item is not InheritableSQLObject: 
     522                item.dropTable(ifExists=True, cascade=True) 
     523 
     524    # list of constraints we will collect 
     525    constraints = list() 
     526 
     527    for item in so_classes: 
     528        if isclass(item) and issubclass(item, SQLObject) and \ 
     529                item is not SQLObject and item is not InheritableSQLObject: 
     530            # create table without applying constraints, collect 
     531            # all the constaints for later creation. 
     532            # see http://sqlobject.org/FAQ.html#mutually-referencing-tables 
     533            # for more info 
     534            collected_constraints = item.createTable(ifNotExists=True, 
     535                applyConstraints=False) 
     536 
     537            if collected_constraints: 
     538                constraints.extend(collected_constraints) 
     539 
     540    # now that all tables are created, add the constaints we collected 
     541    for postponed_constraint in constraints: 
     542        # item is the last processed item and we borrow its connection 
     543        item._connection.query(postponed_constraint) 
     544#elif $identity == 'sqlalchemy' 
     545    get_engine() 
     546    if drop_all: 
     547        print "Dropping all database tables defined in model." 
     548        metadata.drop_all() 
     549    metadata.create_all() 
     550#end if 
     551 
     552    print "All database tables defined in model created." 
     553 
     554def create_default_user(user_name): 
     555    """Create a default user.""" 
     556    from getpass import getpass 
     557 
     558    try: 
     559        u = User.by_user_name(user_name) 
     560    except: 
     561        u = None 
     562    if u: 
     563        print "User '%s' already exists in database." % user_name 
     564        return 
     565    while True: 
     566        try: 
     567            password = getpass("Enter password for user '%s': " 
     568                % user_name).strip() 
     569            password2 = getpass("Confirm password: ").strip() 
     570            if password != password2: 
     571                print "Passwords do not match." 
     572            else: 
     573                password = password.decode(sys.getfilesystemencoding()) 
     574                break 
     575        except (EOFError, KeyboardInterrupt): 
     576            print "User creation cancelled." 
     577            return 
     578#if $identity == 'sqlobject' 
     579    hub.begin() 
     580#end if 
     581    u = User(user_name=user_name, display_name=u"Default User", 
     582        email_address=u"%s@nowhere.xyz" % user_name, password=password) 
     583#if $identity == 'sqlobject' 
     584    hub.commit() 
     585#end if 
     586#if $identity == 'sqlalchemy' 
     587    session.save(u) 
     588    session.flush() 
     589#end if 
     590    print "User '%s' created." % user_name 
  • branches/1.1/turbogears/qstemplates/quickstart/setup.py_tmpl

    r5276 r5756  
    7878        'console_scripts': [ 
    7979            'start-${package} = ${package}.commands:start', 
     80            # See the ${package}.commands.bootstrap function for details 
     81            'bootstrap-${package} = ${package}.commands:bootstrap', 
    8082        ], 
    8183    },