formalchemy.ext.pyramid as moved
@@ -0,0 +1,2 @@
|
||||
*.pyc
|
||||
*.pt.py
|
||||
@@ -0,0 +1,4 @@
|
||||
0.0
|
||||
---
|
||||
|
||||
- Initial version
|
||||
@@ -0,0 +1,4 @@
|
||||
pyramid_formalchemy README
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 Zope Foundation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##############################################################################
|
||||
"""Bootstrap a buildout-based project
|
||||
|
||||
Simply run this script in a directory containing a buildout.cfg.
|
||||
The script accepts buildout command-line options, so you can
|
||||
use the -c option to specify an alternate configuration file.
|
||||
"""
|
||||
|
||||
import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
|
||||
from optparse import OptionParser
|
||||
|
||||
if sys.platform == 'win32':
|
||||
def quote(c):
|
||||
if ' ' in c:
|
||||
return '"%s"' % c # work around spawn lamosity on windows
|
||||
else:
|
||||
return c
|
||||
else:
|
||||
quote = str
|
||||
|
||||
# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
|
||||
stdout, stderr = subprocess.Popen(
|
||||
[sys.executable, '-Sc',
|
||||
'try:\n'
|
||||
' import ConfigParser\n'
|
||||
'except ImportError:\n'
|
||||
' print 1\n'
|
||||
'else:\n'
|
||||
' print 0\n'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||
has_broken_dash_S = bool(int(stdout.strip()))
|
||||
|
||||
# In order to be more robust in the face of system Pythons, we want to
|
||||
# run without site-packages loaded. This is somewhat tricky, in
|
||||
# particular because Python 2.6's distutils imports site, so starting
|
||||
# with the -S flag is not sufficient. However, we'll start with that:
|
||||
if not has_broken_dash_S and 'site' in sys.modules:
|
||||
# We will restart with python -S.
|
||||
args = sys.argv[:]
|
||||
args[0:0] = [sys.executable, '-S']
|
||||
args = map(quote, args)
|
||||
os.execv(sys.executable, args)
|
||||
# Now we are running with -S. We'll get the clean sys.path, import site
|
||||
# because distutils will do it later, and then reset the path and clean
|
||||
# out any namespace packages from site-packages that might have been
|
||||
# loaded by .pth files.
|
||||
clean_path = sys.path[:]
|
||||
import site
|
||||
sys.path[:] = clean_path
|
||||
for k, v in sys.modules.items():
|
||||
if k in ('setuptools', 'pkg_resources') or (
|
||||
hasattr(v, '__path__') and
|
||||
len(v.__path__)==1 and
|
||||
not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
|
||||
# This is a namespace package. Remove it.
|
||||
sys.modules.pop(k)
|
||||
|
||||
is_jython = sys.platform.startswith('java')
|
||||
|
||||
setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
|
||||
distribute_source = 'http://python-distribute.org/distribute_setup.py'
|
||||
|
||||
# parsing arguments
|
||||
def normalize_to_url(option, opt_str, value, parser):
|
||||
if value:
|
||||
if '://' not in value: # It doesn't smell like a URL.
|
||||
value = 'file://%s' % (
|
||||
urllib.pathname2url(
|
||||
os.path.abspath(os.path.expanduser(value))),)
|
||||
if opt_str == '--download-base' and not value.endswith('/'):
|
||||
# Download base needs a trailing slash to make the world happy.
|
||||
value += '/'
|
||||
else:
|
||||
value = None
|
||||
name = opt_str[2:].replace('-', '_')
|
||||
setattr(parser.values, name, value)
|
||||
|
||||
usage = '''\
|
||||
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
|
||||
|
||||
Bootstraps a buildout-based project.
|
||||
|
||||
Simply run this script in a directory containing a buildout.cfg, using the
|
||||
Python that you want bin/buildout to use.
|
||||
|
||||
Note that by using --setup-source and --download-base to point to
|
||||
local resources, you can keep this script from going over the network.
|
||||
'''
|
||||
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-v", "--version", dest="version",
|
||||
help="use a specific zc.buildout version")
|
||||
parser.add_option("-d", "--distribute",
|
||||
action="store_true", dest="use_distribute", default=False,
|
||||
help="Use Distribute rather than Setuptools.")
|
||||
parser.add_option("--setup-source", action="callback", dest="setup_source",
|
||||
callback=normalize_to_url, nargs=1, type="string",
|
||||
help=("Specify a URL or file location for the setup file. "
|
||||
"If you use Setuptools, this will default to " +
|
||||
setuptools_source + "; if you use Distribute, this "
|
||||
"will default to " + distribute_source +"."))
|
||||
parser.add_option("--download-base", action="callback", dest="download_base",
|
||||
callback=normalize_to_url, nargs=1, type="string",
|
||||
help=("Specify a URL or directory for downloading "
|
||||
"zc.buildout and either Setuptools or Distribute. "
|
||||
"Defaults to PyPI."))
|
||||
parser.add_option("--eggs",
|
||||
help=("Specify a directory for storing eggs. Defaults to "
|
||||
"a temporary directory that is deleted when the "
|
||||
"bootstrap script completes."))
|
||||
parser.add_option("-t", "--accept-buildout-test-releases",
|
||||
dest='accept_buildout_test_releases',
|
||||
action="store_true", default=False,
|
||||
help=("Normally, if you do not specify a --version, the "
|
||||
"bootstrap script and buildout gets the newest "
|
||||
"*final* versions of zc.buildout and its recipes and "
|
||||
"extensions for you. If you use this flag, "
|
||||
"bootstrap and buildout will get the newest releases "
|
||||
"even if they are alphas or betas."))
|
||||
parser.add_option("-c", None, action="store", dest="config_file",
|
||||
help=("Specify the path to the buildout configuration "
|
||||
"file to be used."))
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# if -c was provided, we push it back into args for buildout's main function
|
||||
if options.config_file is not None:
|
||||
args += ['-c', options.config_file]
|
||||
|
||||
if options.eggs:
|
||||
eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
|
||||
else:
|
||||
eggs_dir = tempfile.mkdtemp()
|
||||
|
||||
if options.setup_source is None:
|
||||
if options.use_distribute:
|
||||
options.setup_source = distribute_source
|
||||
else:
|
||||
options.setup_source = setuptools_source
|
||||
|
||||
if options.accept_buildout_test_releases:
|
||||
args.append('buildout:accept-buildout-test-releases=true')
|
||||
args.append('bootstrap')
|
||||
|
||||
try:
|
||||
import pkg_resources
|
||||
import setuptools # A flag. Sometimes pkg_resources is installed alone.
|
||||
if not hasattr(pkg_resources, '_distribute'):
|
||||
raise ImportError
|
||||
except ImportError:
|
||||
ez_code = urllib2.urlopen(
|
||||
options.setup_source).read().replace('\r\n', '\n')
|
||||
ez = {}
|
||||
exec ez_code in ez
|
||||
setup_args = dict(to_dir=eggs_dir, download_delay=0)
|
||||
if options.download_base:
|
||||
setup_args['download_base'] = options.download_base
|
||||
if options.use_distribute:
|
||||
setup_args['no_fake'] = True
|
||||
ez['use_setuptools'](**setup_args)
|
||||
if 'pkg_resources' in sys.modules:
|
||||
reload(sys.modules['pkg_resources'])
|
||||
import pkg_resources
|
||||
# This does not (always?) update the default working set. We will
|
||||
# do it.
|
||||
for path in sys.path:
|
||||
if path not in pkg_resources.working_set.entries:
|
||||
pkg_resources.working_set.add_entry(path)
|
||||
|
||||
cmd = [quote(sys.executable),
|
||||
'-c',
|
||||
quote('from setuptools.command.easy_install import main; main()'),
|
||||
'-mqNxd',
|
||||
quote(eggs_dir)]
|
||||
|
||||
if not has_broken_dash_S:
|
||||
cmd.insert(1, '-S')
|
||||
|
||||
find_links = options.download_base
|
||||
if not find_links:
|
||||
find_links = os.environ.get('bootstrap-testing-find-links')
|
||||
if find_links:
|
||||
cmd.extend(['-f', quote(find_links)])
|
||||
|
||||
if options.use_distribute:
|
||||
setup_requirement = 'distribute'
|
||||
else:
|
||||
setup_requirement = 'setuptools'
|
||||
ws = pkg_resources.working_set
|
||||
setup_requirement_path = ws.find(
|
||||
pkg_resources.Requirement.parse(setup_requirement)).location
|
||||
env = dict(
|
||||
os.environ,
|
||||
PYTHONPATH=setup_requirement_path)
|
||||
|
||||
requirement = 'zc.buildout'
|
||||
version = options.version
|
||||
if version is None and not options.accept_buildout_test_releases:
|
||||
# Figure out the most recent final version of zc.buildout.
|
||||
import setuptools.package_index
|
||||
_final_parts = '*final-', '*final'
|
||||
def _final_version(parsed_version):
|
||||
for part in parsed_version:
|
||||
if (part[:1] == '*') and (part not in _final_parts):
|
||||
return False
|
||||
return True
|
||||
index = setuptools.package_index.PackageIndex(
|
||||
search_path=[setup_requirement_path])
|
||||
if find_links:
|
||||
index.add_find_links((find_links,))
|
||||
req = pkg_resources.Requirement.parse(requirement)
|
||||
if index.obtain(req) is not None:
|
||||
best = []
|
||||
bestv = None
|
||||
for dist in index[req.project_name]:
|
||||
distv = dist.parsed_version
|
||||
if _final_version(distv):
|
||||
if bestv is None or distv > bestv:
|
||||
best = [dist]
|
||||
bestv = distv
|
||||
elif distv == bestv:
|
||||
best.append(dist)
|
||||
if best:
|
||||
best.sort()
|
||||
version = best[-1].version
|
||||
if version:
|
||||
requirement = '=='.join((requirement, version))
|
||||
cmd.append(requirement)
|
||||
|
||||
if is_jython:
|
||||
import subprocess
|
||||
exitcode = subprocess.Popen(cmd, env=env).wait()
|
||||
else: # Windows prefers this, apparently; otherwise we would prefer subprocess
|
||||
exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
|
||||
if exitcode != 0:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
print ("An error occurred when trying to install zc.buildout. "
|
||||
"Look above this message for any errors that "
|
||||
"were output by easy_install.")
|
||||
sys.exit(exitcode)
|
||||
|
||||
ws.add_entry(eggs_dir)
|
||||
ws.require(requirement)
|
||||
import zc.buildout.buildout
|
||||
zc.buildout.buildout.main(args)
|
||||
if not options.eggs: # clean up temporary egg directory
|
||||
shutil.rmtree(eggs_dir)
|
||||
@@ -0,0 +1,25 @@
|
||||
[buildout]
|
||||
newest = false
|
||||
extensions = gp.vcsdevelop
|
||||
parts = eggs test
|
||||
develop = . pyramidapp
|
||||
|
||||
[eggs]
|
||||
recipe = zc.recipe.egg
|
||||
eggs =
|
||||
pyramid_formalchemy
|
||||
pyramidapp
|
||||
WebTest
|
||||
PasteScript
|
||||
Sphinx
|
||||
|
||||
[test]
|
||||
recipe = zc.recipe.egg
|
||||
eggs =
|
||||
${eggs:eggs}
|
||||
nose
|
||||
initialization =
|
||||
import os
|
||||
os.chdir('pyramidapp')
|
||||
scripts=
|
||||
nosetests=nosetests
|
||||
@@ -0,0 +1,44 @@
|
||||
[app:pyramid_formalchemy]
|
||||
use = egg:pyramid_formalchemy
|
||||
reload_templates = true
|
||||
debug_authorization = false
|
||||
debug_notfound = false
|
||||
debug_routematch = false
|
||||
debug_templates = true
|
||||
default_locale_name = en
|
||||
|
||||
[pipeline:main]
|
||||
pipeline =
|
||||
egg:WebError#evalerror
|
||||
pyramid_formalchemy
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 6543
|
||||
|
||||
# Begin logging configuration
|
||||
|
||||
[loggers]
|
||||
keys = root
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
|
||||
|
||||
# End logging configuration
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
def include_formalchemy(config):
|
||||
pass
|
||||
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0"?>
|
||||
<configure xmlns="http://pylonshq.com/pyramid">
|
||||
|
||||
<include package="pyramid.includes" />
|
||||
|
||||
<static
|
||||
name="fa_admin"
|
||||
path="pyramid_formalchemy:static"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.AdminView"
|
||||
view=".views.ModelView"
|
||||
attr="models"
|
||||
request_method="GET"
|
||||
renderer="pyramid_formalchemy:templates/admin/models.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelListing"
|
||||
view=".views.ModelView"
|
||||
attr="listing"
|
||||
request_method="GET"
|
||||
renderer="pyramid_formalchemy:templates/admin/listing.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name="new"
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelListing"
|
||||
view=".views.ModelView"
|
||||
attr="new"
|
||||
request_method="GET"
|
||||
renderer="pyramid_formalchemy:templates/admin/new.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelListing"
|
||||
view=".views.ModelView"
|
||||
attr="create"
|
||||
request_method="POST"
|
||||
renderer="pyramid_formalchemy:templates/admin/new.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name="edit"
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="edit"
|
||||
request_method="GET"
|
||||
renderer="pyramid_formalchemy:templates/admin/edit.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name="edit"
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="update"
|
||||
request_method="POST"
|
||||
renderer="pyramid_formalchemy:templates/admin/edit.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="update"
|
||||
request_method="POST"
|
||||
renderer="json"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="update"
|
||||
request_method="PUT"
|
||||
renderer="json"
|
||||
/>
|
||||
|
||||
|
||||
<view
|
||||
name="delete"
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="delete"
|
||||
request_method="POST"
|
||||
renderer="pyramid_formalchemy:templates/admin/edit.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="delete"
|
||||
request_method="DELETE"
|
||||
renderer="pyramid_formalchemy:templates/admin/edit.pt"
|
||||
/>
|
||||
|
||||
<view
|
||||
name=""
|
||||
route_name="fa_admin"
|
||||
context=".resources.ModelItem"
|
||||
view=".views.ModelView"
|
||||
attr="show"
|
||||
request_method="GET"
|
||||
renderer="pyramid_formalchemy:templates/admin/show.pt"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class AdminView(object):
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
request.model_name = None
|
||||
request.model_id = None
|
||||
request.format = 'html'
|
||||
self.__parent__ = self.__name__ = None
|
||||
def __getitem__(self, item):
|
||||
if item in ('json',):
|
||||
self.request.format = item
|
||||
return self
|
||||
model = ModelListing(self.request, item)
|
||||
model.__parent__ = self
|
||||
return model
|
||||
|
||||
class ModelListing(object):
|
||||
def __init__(self, request, name):
|
||||
self.request = request
|
||||
request.model_name = name
|
||||
self.__name__ = name
|
||||
self.__parent__ = None
|
||||
def __getitem__(self, item):
|
||||
if item in ('json',):
|
||||
self.request.format = item
|
||||
return self
|
||||
if item in ('new',):
|
||||
raise KeyError()
|
||||
model = ModelItem(self.request, item)
|
||||
model.__parent__ = self
|
||||
return model
|
||||
|
||||
class ModelItem(object):
|
||||
def __init__(self, request, name):
|
||||
request.model_id = name
|
||||
self.__name__ = name
|
||||
self.__parent__ = None
|
||||
|
||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1,470 @@
|
||||
/**
|
||||
* Blue Box main CSS file
|
||||
* @version 1.0.0
|
||||
* @author Aaron D. Campbell http://xavisys.com/
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
border: 0;
|
||||
font-family: inherit;
|
||||
font-size: 100%;
|
||||
font-style: inherit;
|
||||
font-weight: inherit;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-weight:bold;
|
||||
}
|
||||
h1 {
|
||||
font-size:2em;
|
||||
}
|
||||
h2 {
|
||||
font-size:1.5em;
|
||||
}
|
||||
h3 {
|
||||
font-size:1.3em;
|
||||
}
|
||||
h4 {
|
||||
font-size:1.1em;
|
||||
}
|
||||
h5 {
|
||||
font-size:1em;
|
||||
}
|
||||
h6 {
|
||||
font-size:.8em;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color:#D5D6D7;
|
||||
color:#333;
|
||||
font:80% Verdana,"Trebuchet MS",Georgia,"Times New Roman",Times,serif;
|
||||
margin:20px;
|
||||
min-width:675px;
|
||||
padding:0pt;
|
||||
}
|
||||
|
||||
table {
|
||||
margin:1em;
|
||||
}
|
||||
|
||||
table, table tr {
|
||||
border-collapse:collapse;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
|
||||
table th,
|
||||
table td {
|
||||
border:thin solid #D5D6D7;
|
||||
border-collapse:collapse;
|
||||
margin:0;
|
||||
padding:0.2em 0.5em;
|
||||
}
|
||||
|
||||
table th {
|
||||
font-weight:bold;
|
||||
background:#EFEFEF;
|
||||
}
|
||||
|
||||
td a {
|
||||
display:block;
|
||||
}
|
||||
|
||||
tr.odd {
|
||||
background:#EFEFEF;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height:1.5em;
|
||||
margin:1em 0;
|
||||
}
|
||||
|
||||
#header {
|
||||
background-color:#73A0C5;
|
||||
border:1px solid #666;
|
||||
border-bottom:none;
|
||||
height:70px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
#title {
|
||||
float:left;
|
||||
margin:5px 0 0 1em;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
font-size:2em;
|
||||
padding:0pt;
|
||||
}
|
||||
#header #tagline {
|
||||
color:#DDD;
|
||||
font-size:0.9em;
|
||||
font-style:italic;
|
||||
margin:0;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
#header h1,
|
||||
#header h1 a,
|
||||
#header h1 a:hover,
|
||||
#header h1 a:visited {
|
||||
color:#FFF;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
h1#header {
|
||||
color: white;
|
||||
height: 1.5em;
|
||||
padding: 0.3em 1em;
|
||||
}
|
||||
|
||||
h1#header a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.breadcrumb { float:right; font-size: 0.7em;}
|
||||
|
||||
#nav {
|
||||
bottom:0;
|
||||
position:absolute;
|
||||
right:0;
|
||||
}
|
||||
|
||||
#nav a {
|
||||
background-color:#EFEFEF;
|
||||
border:1px solid #666;
|
||||
border-bottom:0;
|
||||
color:#259;
|
||||
font-size:1.2em;
|
||||
font-weight:bold;
|
||||
margin:0 .1em;
|
||||
padding:.2em;
|
||||
padding-bottom:0;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
#nav a:hover,
|
||||
#nav a.current {
|
||||
background-color:#FFF;
|
||||
}
|
||||
|
||||
#content {
|
||||
background-color:#FFF;
|
||||
border:1px solid #666;
|
||||
border-width:0 1px;
|
||||
padding:1em;
|
||||
}
|
||||
#content ol {
|
||||
margin-left:2em;
|
||||
}
|
||||
#content ul {
|
||||
margin-left:1.5em;
|
||||
}
|
||||
#sidebar {
|
||||
float:right;
|
||||
margin:1em;
|
||||
width:260px;
|
||||
}
|
||||
#sidebar .box p {
|
||||
background-color:#F2F2F2;
|
||||
margin:.5em;
|
||||
}
|
||||
#sidebar .box ul li {
|
||||
border-bottom:1px solid #73A0C5;
|
||||
list-style-type:none;
|
||||
}
|
||||
#sidebar .box ul li a {
|
||||
display:block;
|
||||
padding:.5em;
|
||||
}
|
||||
#sidebar .box label {
|
||||
display:block;
|
||||
float:left;
|
||||
height:21px;
|
||||
margin-right:10px;
|
||||
width:70px;
|
||||
}
|
||||
#footer {
|
||||
background-color:#EFEFEF;
|
||||
border:1px solid #666;
|
||||
border-top:none;
|
||||
font-size:.8em;
|
||||
padding:1em;
|
||||
text-align:center;
|
||||
}
|
||||
#footer p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
a,
|
||||
a:link {
|
||||
color:#06C;
|
||||
text-decoration:none;
|
||||
}
|
||||
a:visited {
|
||||
color:#147;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
color:#147;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
blockquote,
|
||||
code {
|
||||
background-color:#F2F2F2;
|
||||
border-left:4px solid #73A0C5;
|
||||
display:block;
|
||||
font-style:oblique;
|
||||
line-height:20px;
|
||||
margin:0 1em;
|
||||
padding:0 1em;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
.box{
|
||||
border:1px solid #999;
|
||||
margin:0 0 1em 0;
|
||||
overflow:auto;
|
||||
}
|
||||
.box p,
|
||||
.box ul,
|
||||
.box ol,
|
||||
.box div.cont,
|
||||
.box form {
|
||||
margin:.5em;
|
||||
}
|
||||
.box h1,
|
||||
.box h2,
|
||||
.box h3,
|
||||
.box h4,
|
||||
.box h5,
|
||||
.box h6 {
|
||||
background-color:#73A0C5;
|
||||
display:block;
|
||||
padding:0 5px;
|
||||
color:white;
|
||||
}
|
||||
.more {
|
||||
display:block;
|
||||
font-size:.8em;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
/*********
|
||||
* Forms *
|
||||
*********/
|
||||
.admin-flash,
|
||||
fieldset {
|
||||
color:#777;
|
||||
margin-top:15px;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.admin-flash {
|
||||
background:#EFEFEF;
|
||||
margin-bottom:15px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.message,
|
||||
fieldset,
|
||||
input,
|
||||
button,
|
||||
fieldset textarea,
|
||||
fieldset select {
|
||||
border:1px solid #F5F5F5;
|
||||
border-left-color:#DDD;
|
||||
border-top-color:#DDD;
|
||||
}
|
||||
|
||||
legend {
|
||||
color:#73A0C5;
|
||||
font-weight:bold;
|
||||
padding:5px 10px;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
fieldset textarea,
|
||||
fieldset select {
|
||||
color:#777;
|
||||
font:90% Verdana;
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
fieldset textarea {
|
||||
width:430px;
|
||||
}
|
||||
|
||||
option {
|
||||
padding:0 10px 0 5px;
|
||||
}
|
||||
fieldset label,
|
||||
fieldset p.label {
|
||||
color:#777;
|
||||
text-align:right;
|
||||
width:145px;
|
||||
}
|
||||
fieldset label {
|
||||
float:left;
|
||||
margin:5px 0;
|
||||
margin-right:10px;
|
||||
}
|
||||
|
||||
fieldset p {
|
||||
margin:0;
|
||||
}
|
||||
fieldset div {
|
||||
padding:5px 0;
|
||||
position:relative;
|
||||
}
|
||||
fieldset div div {
|
||||
margin:0;
|
||||
}
|
||||
fieldset p.label {
|
||||
left:0;
|
||||
position:absolute;
|
||||
}
|
||||
|
||||
.radio {
|
||||
margin-left:160px;
|
||||
}
|
||||
.radio label,
|
||||
.radio input {
|
||||
background:none;
|
||||
border:none;
|
||||
display:inline;
|
||||
float:none;
|
||||
vertical-align:middle;
|
||||
width:auto;
|
||||
}
|
||||
.radio div {
|
||||
clear:none;
|
||||
white-space:nowrap;
|
||||
}
|
||||
#sidebar form {
|
||||
margin:0 0 1em 0;
|
||||
}
|
||||
|
||||
.submit,
|
||||
#sidebar .submit {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
.ui-widget-link,
|
||||
.submit input,
|
||||
#sidebar .submit input {
|
||||
background-color:#F9F9F9;
|
||||
border:1px solid #F5F5F5;
|
||||
border-left-color:#DDD;
|
||||
border-top-color:#DDD;
|
||||
cursor:pointer;
|
||||
padding:0 21px;
|
||||
text-transform:lowercase;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.ui-widget-link input {
|
||||
border:0px;
|
||||
background:transparent;
|
||||
}
|
||||
|
||||
a.ui-widget-link {
|
||||
color:#777777;
|
||||
font-family:Verdana;
|
||||
}
|
||||
|
||||
.ui-widget-link {
|
||||
cursor:pointer;
|
||||
margin-right:0.3em;
|
||||
}
|
||||
|
||||
|
||||
td form { text-align:center;}
|
||||
|
||||
td input.ui-icon {
|
||||
background-color:transparent;
|
||||
border:0px;
|
||||
width:16px;
|
||||
height: 0px;
|
||||
overflow:hidden;
|
||||
padding-bottom:13px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui-icon-pencil {
|
||||
background-image: url(./edit.png);
|
||||
}
|
||||
.ui-icon-circle-close {
|
||||
background-image: url(./delete.png);
|
||||
}
|
||||
|
||||
#sidebar input {
|
||||
border:1px solid #DDD;
|
||||
border-bottom-color:#F5F5F5;
|
||||
border-right-color:#F5F5F5;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#sidebar label {
|
||||
height:auto;
|
||||
margin-bottom:0;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.button {
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.form_controls {
|
||||
margin-left:155px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display:block;
|
||||
height:0px;
|
||||
padding-top:16px;
|
||||
width:16px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
input.icon {
|
||||
border:none;
|
||||
width:16px;
|
||||
height:16px;
|
||||
padding:0;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#pager {
|
||||
text-align: center;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
#pager a, #pager .pager_curpage {
|
||||
padding: 0 0.2em;
|
||||
border:thin solid #114477;
|
||||
background: #73A0C5;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#pager a:hover, #pager .pager_curpage {
|
||||
text-decoration:none;
|
||||
background:white;
|
||||
color:#114477;
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 574 B |
@@ -0,0 +1,13 @@
|
||||
<html metal:use-macro="main.macros['master']">
|
||||
<body>
|
||||
<div metal:fill-slot="main">
|
||||
<form action="" method="POST" enctype="multipart/form-data">
|
||||
<div tal:content="structure fs.render()" />
|
||||
<input type="hidden" name="_method" value="PUT" />
|
||||
<div metal:use-macro="main.macros['buttons']">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<html metal:use-macro="main.macros['master']">
|
||||
<body>
|
||||
<div metal:fill-slot="main">
|
||||
<div class="ui-pager" tal:content="structure pager" />
|
||||
<table class="layout-grid" tal:content="structure fs.render()" />
|
||||
<p>
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all"
|
||||
tal:attributes="href request.route_url('fa_admin', traverse='%s/new' % request.model_name)">
|
||||
<span class="ui-icon ui-icon-circle-plus"></span>
|
||||
${F_('New')} ${model_name}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<html metal:define-macro="master">
|
||||
<head>
|
||||
<title tal:content="request.model_name or 'root'"></title>
|
||||
<link rel="stylesheet" tal:attributes="href request.static_url('pyramid_formalchemy:static/admin.css')"></link>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" class="ui-admin ui-widget">
|
||||
<h1 id="header" class="ui-widget-header ui-corner-all">
|
||||
<div class="breadcrumb">
|
||||
<tal:repeat tal:repeat="item breadcrumb">
|
||||
<a tal:attributes="href python:item[0]"
|
||||
tal:content="python:item[1]" />
|
||||
<span tal:condition="not repeat.item.end">/</span>
|
||||
</tal:repeat>
|
||||
</div>
|
||||
<div tal:content="request.model_name or 'root'"></div>
|
||||
</h1>
|
||||
<div metal:define-slot="main">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<div metal:define-macro="buttons">
|
||||
<p class="fa_field">
|
||||
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all" href="#">
|
||||
<input type="submit" value="${F_('Save')}" />
|
||||
</a>
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all"
|
||||
tal:attributes="href request.route_url('fa_admin', traverse=request.model_name)">
|
||||
<span class="ui-icon ui-icon-circle-arrow-w"></span>
|
||||
${F_('Cancel')}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<html metal:use-macro="main.macros['master']">
|
||||
<body>
|
||||
<div metal:fill-slot="main">
|
||||
<div tal:repeat="item models">
|
||||
<div>
|
||||
<a tal:attributes="href request.route_url('fa_admin', traverse=item)"
|
||||
tal:content="item"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<html metal:use-macro="main.macros['master']">
|
||||
<body>
|
||||
<div metal:fill-slot="main">
|
||||
<form method="POST" enctype="multipart/form-data"
|
||||
tal:attributes="action request.route_url('fa_admin', traverse=request.model_name)"
|
||||
>
|
||||
<div tal:content="structure fs.render()" />
|
||||
<div metal:use-macro="main.macros['buttons']">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
{{if template_engine == 'mako'}}
|
||||
# -*- coding: utf-8 -*-
|
||||
<%!
|
||||
from formalchemy.ext.pylons.controller import model_url
|
||||
from pylons import url
|
||||
%>
|
||||
<%def name="h1(title, href=None)">
|
||||
<h1 id="header" class="ui-widget-header ui-corner-all">
|
||||
%if breadcrumb:
|
||||
<div class="breadcrumb">
|
||||
/${'/'.join([u and '<a href="%s">%s</a>' % (u,n.lower()) or n.lower() for u,n in breadcrumb])|n}
|
||||
</div>
|
||||
%endif
|
||||
%if href:
|
||||
<a href="${href}">${title.title()}</a>
|
||||
%else:
|
||||
${title.title()}
|
||||
%endif
|
||||
</h1>
|
||||
</%def>
|
||||
<%def name="buttons()">
|
||||
<p class="fa_field">
|
||||
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all" href="#">
|
||||
<input type="submit" value="${F_('Save')}" />
|
||||
</a>
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all" href="${model_url(collection_name)}">
|
||||
<span class="ui-icon ui-icon-circle-arrow-w"></span>
|
||||
${F_('Cancel')}
|
||||
</a>
|
||||
</p>
|
||||
</%def>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
${collection_name.title()}
|
||||
</title>
|
||||
<link rel="stylesheet" type="text/css" href="${url('fa_static', path_info='/admin.css')}" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" class="ui-admin ui-widget">
|
||||
%if isinstance(models, dict):
|
||||
<h1 id="header" class="ui-widget-header ui-corner-all">${F_('Models')}</h1>
|
||||
%for name in sorted(models):
|
||||
<p>
|
||||
<a class="ui-state-default ui-corner-all" href="${models[name]}">${name}</a>
|
||||
</p>
|
||||
%endfor
|
||||
%elif is_grid:
|
||||
${h1(model_name)}
|
||||
<div class="ui-pager">
|
||||
${pager|n}
|
||||
</div>
|
||||
<table class="layout-grid">
|
||||
${fs.render()|n}
|
||||
</table>
|
||||
<p>
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all" href="${model_url('new_%s' % member_name)}">
|
||||
<span class="ui-icon ui-icon-circle-plus"></span>
|
||||
${F_('New')} ${model_name}
|
||||
</a>
|
||||
</p>
|
||||
%else:
|
||||
${h1(model_name, href=model_url(collection_name))}
|
||||
%if action == 'show':
|
||||
<table>
|
||||
${fs.render()|n}
|
||||
</table>
|
||||
<p class="fa_field">
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all" href="${model_url('edit_%s' % member_name, id=id)}">
|
||||
<span class="ui-icon ui-icon-pencil"></span>
|
||||
${F_('Edit')}
|
||||
</a>
|
||||
</p>
|
||||
%elif action == 'edit':
|
||||
<form action="${model_url(member_name, id=id)}" method="POST" enctype="multipart/form-data">
|
||||
${fs.render()|n}
|
||||
<input type="hidden" name="_method" value="PUT" />
|
||||
${buttons()}
|
||||
</form>
|
||||
%else:
|
||||
<form action="${model_url(collection_name)}" method="POST" enctype="multipart/form-data">
|
||||
${fs.render()|n}
|
||||
${buttons()}
|
||||
</form>
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var icons = document.getElementsByClassName('ui-icon')
|
||||
for (var i = 0; i < icons.length-1; i++) {
|
||||
icons[i].setAttribute('value', ' ');
|
||||
}
|
||||
</script>
|
||||
</body></html>
|
||||
{{endif}}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<html metal:use-macro="main.macros['master']">
|
||||
<body>
|
||||
<div metal:fill-slot="main">
|
||||
<div tal:content="structure fs.render()" />
|
||||
<div metal:use-macro="main.macros['buttons']">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
|
||||
<head>
|
||||
<title>The Pyramid Web Application Development Framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
<meta name="keywords" content="python web application" />
|
||||
<meta name="description" content="pyramid web application" />
|
||||
<link rel="shortcut icon" href="${request.static_url('pyramid_formalchemy:static/favicon.ico')}" />
|
||||
<link rel="stylesheet" href="${request.static_url('pyramid_formalchemy:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
||||
<!--[if lte IE 6]>
|
||||
<link rel="stylesheet" href="${request.static_url('pyramid_formalchemy:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="top">
|
||||
<div class="top align-center">
|
||||
<div><img src="${request.static_url('pyramid_formalchemy:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="middle">
|
||||
<div class="middle align-center">
|
||||
<p class="app-welcome">
|
||||
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
|
||||
the Pyramid web application development framework.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bottom">
|
||||
<div class="bottom">
|
||||
<div id="left" class="align-right">
|
||||
<h2>Search documentation</h2>
|
||||
<form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
|
||||
<input type="text" id="q" name="q" value="" />
|
||||
<input type="submit" id="x" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="right" class="align-left">
|
||||
<h2>Pyramid links</h2>
|
||||
<ul class="links">
|
||||
<li>
|
||||
<a href="http://pylonshq.com">Pylons Website</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,458 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
from webhelpers.paginate import Page
|
||||
from sqlalchemy.orm import class_mapper, object_session
|
||||
from formalchemy.fields import _pk
|
||||
from formalchemy.fields import _stringify
|
||||
from formalchemy import Grid, FieldSet
|
||||
from formalchemy.i18n import get_translator
|
||||
from formalchemy.fields import Field
|
||||
from formalchemy import fatypes
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render
|
||||
from pyramid.renderers import get_renderer
|
||||
from pyramid import httpexceptions as exc
|
||||
|
||||
try:
|
||||
from formalchemy.ext.couchdb import Document
|
||||
except ImportError:
|
||||
Document = None
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
class Session(object):
|
||||
"""A abstract class to implement other backend than SA"""
|
||||
def add(self, record):
|
||||
"""add a record"""
|
||||
def update(self, record):
|
||||
"""update a record"""
|
||||
def delete(self, record):
|
||||
"""delete a record"""
|
||||
def commit(self):
|
||||
"""commit transaction"""
|
||||
|
||||
class ModelView(object):
|
||||
"""A RESTful view bound to a model"""
|
||||
|
||||
engine = prefix_name = None
|
||||
pager_args = dict(link_attr={'class': 'ui-pager-link ui-state-default ui-corner-all'},
|
||||
curpage_attr={'class': 'ui-pager-curpage ui-state-highlight ui-corner-all'})
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
self.settings = request.registry.settings
|
||||
self.model = self.settings['fa.models']
|
||||
self.forms = self.settings.get('fa.forms', None)
|
||||
self.FieldSet = self.settings.get('fa.fieldset', FieldSet)
|
||||
self.Grid = self.settings.get('fa.grid', Grid)
|
||||
|
||||
@property
|
||||
def model_name(self):
|
||||
"""return ``model_name`` from ``pylons.routes_dict``"""
|
||||
try:
|
||||
return self.request.model_name
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
def route_url(self, *args):
|
||||
return self.request.route_url('fa_admin', traverse='/'.join([str(a) for a in args]))
|
||||
|
||||
def Session(self):
|
||||
"""return a Session object. You **must** override this."""
|
||||
return self.settings['fa.session_factory']()
|
||||
|
||||
def models(self, **kwargs):
|
||||
"""Models index page"""
|
||||
request = self.request
|
||||
models = {}
|
||||
if isinstance(self.model, list):
|
||||
for model in self.model:
|
||||
key = model.__name__
|
||||
models[key] = self.route_url(key, request.format)
|
||||
else:
|
||||
for key, obj in self.model.__dict__.iteritems():
|
||||
if not key.startswith('_'):
|
||||
if Document is not None:
|
||||
try:
|
||||
if issubclass(obj, Document):
|
||||
models[key] = self.route_url(key, request.format)
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
class_mapper(obj)
|
||||
except:
|
||||
continue
|
||||
if not isinstance(obj, type):
|
||||
continue
|
||||
models[key] = self.route_url(key, request.format)
|
||||
return self.render(models=models)
|
||||
|
||||
def get_model(self):
|
||||
if isinstance(self.model, list):
|
||||
for model in self.model:
|
||||
if model.__name__ == self.model_name:
|
||||
return model
|
||||
elif hasattr(self.model, self.model_name):
|
||||
return getattr(self.model, self.model_name)
|
||||
raise exc.HTTPNotFound(description='model %s not found' % self.model_name)
|
||||
|
||||
def get_fieldset(self, id):
|
||||
if self.forms and hasattr(self.forms, self.model_name):
|
||||
fs = getattr(self.forms, self.model_name)
|
||||
fs.engine = fs.engine or self.engine
|
||||
return id and fs.bind(self.get(id)) or fs
|
||||
raise KeyError(self.model_name)
|
||||
|
||||
def get_add_fieldset(self):
|
||||
if self.forms and hasattr(self.forms, '%sAdd' % self.model_name):
|
||||
fs = getattr(self.forms, '%sAdd' % self.model_name)
|
||||
fs.engine = fs.engine or self.engine
|
||||
return fs
|
||||
return self.get_fieldset(id=None)
|
||||
|
||||
def get_grid(self):
|
||||
model_name = self.model_name
|
||||
if self.forms and hasattr(self.forms, '%sGrid' % model_name):
|
||||
g = getattr(self.forms, '%sGrid' % model_name)
|
||||
g.engine = g.engine or self.engine
|
||||
g.readonly = True
|
||||
self.update_grid(g)
|
||||
return g
|
||||
raise KeyError(self.model_name)
|
||||
|
||||
def sync(self, fs, id=None):
|
||||
"""sync a record. If ``id`` is None add a new record else save current one.
|
||||
|
||||
Default is::
|
||||
|
||||
S = self.Session()
|
||||
if id:
|
||||
S.merge(fs.model)
|
||||
else:
|
||||
S.add(fs.model)
|
||||
S.commit()
|
||||
"""
|
||||
S = self.Session()
|
||||
if id:
|
||||
S.merge(fs.model)
|
||||
else:
|
||||
S.add(fs.model)
|
||||
|
||||
def breadcrumb(self, fs=None, **kwargs):
|
||||
"""return items to build the breadcrumb"""
|
||||
items = []
|
||||
request = self.request
|
||||
model_name = request.model_name
|
||||
id = request.model_id
|
||||
items.append((self.route_url(), 'root'))
|
||||
if self.model_name:
|
||||
items.append((self.route_url(model_name), model_name))
|
||||
if id and hasattr(fs.model, '__unicode__'):
|
||||
items.append((self.route_url(model_name, id), u'%s' % fs.model))
|
||||
elif id:
|
||||
items.append((self.route_url(model_name, id), id))
|
||||
return items
|
||||
|
||||
def render(self, **kwargs):
|
||||
"""render the form as html or json"""
|
||||
request = self.request
|
||||
if request.format != 'html':
|
||||
meth = getattr(self, 'render_%s_format' % request.format, None)
|
||||
if meth is not None:
|
||||
return meth(**kwargs)
|
||||
else:
|
||||
return exc.HTTPNotfound()
|
||||
kwargs.update(
|
||||
main = get_renderer('pyramid_formalchemy:templates/admin/master.pt').implementation(),
|
||||
model_name=self.model_name,
|
||||
breadcrumb=self.breadcrumb(**kwargs),
|
||||
F_=get_translator().gettext)
|
||||
return kwargs
|
||||
|
||||
def render_grid(self, **kwargs):
|
||||
"""render the grid as html or json"""
|
||||
return self.render(is_grid=True, **kwargs)
|
||||
|
||||
def render_json_format(self, fs=None, **kwargs):
|
||||
request = self.request
|
||||
request.override_renderer = 'json'
|
||||
if fs:
|
||||
try:
|
||||
fields = fs.jsonify()
|
||||
except AttributeError:
|
||||
fields = dict([(field.renderer.name, field.model_value) for field in fs.render_fields.values()])
|
||||
data = dict(fields=fields)
|
||||
pk = _pk(fs.model)
|
||||
if pk:
|
||||
data['item_url'] = request.route_url('fa_admin', traverse='%s/json/%s' % (self.model_name, pk))
|
||||
else:
|
||||
data = {}
|
||||
data.update(kwargs)
|
||||
return data
|
||||
|
||||
def render_xhr_format(self, fs=None, **kwargs):
|
||||
response.content_type = 'text/html'
|
||||
if fs is not None:
|
||||
if 'field' in request.GET:
|
||||
field_name = request.GET.get('field')
|
||||
fields = fs.render_fields
|
||||
if field_name in fields:
|
||||
field = fields[field_name]
|
||||
return field.render()
|
||||
else:
|
||||
return exc.HTTPNotfound()
|
||||
return fs.render()
|
||||
return ''
|
||||
|
||||
def get_page(self, **kwargs):
|
||||
"""return a ``webhelpers.paginate.Page`` used to display ``Grid``.
|
||||
|
||||
Default is::
|
||||
|
||||
S = self.Session()
|
||||
query = S.query(self.get_model())
|
||||
kwargs = request.environ.get('pylons.routes_dict', {})
|
||||
return Page(query, page=int(request.GET.get('page', '1')), **kwargs)
|
||||
"""
|
||||
S = self.Session()
|
||||
def get_page_url(page, partial=None):
|
||||
url = "%s?page=%s" % (self.request.path, page)
|
||||
if partial:
|
||||
url += "&partial=1"
|
||||
return url
|
||||
options = dict(collection=S.query(self.get_model()),
|
||||
page=int(self.request.GET.get('page', '1')),
|
||||
url=get_page_url)
|
||||
options.update(kwargs)
|
||||
collection = options.pop('collection')
|
||||
return Page(collection, **options)
|
||||
|
||||
def get(self, id=None):
|
||||
"""return correct record for ``id`` or a new instance.
|
||||
|
||||
Default is::
|
||||
|
||||
S = self.Session()
|
||||
model = self.get_model()
|
||||
if id:
|
||||
model = S.query(model).get(id)
|
||||
else:
|
||||
model = model()
|
||||
return model or abort(404)
|
||||
|
||||
"""
|
||||
S = self.Session()
|
||||
model = self.get_model()
|
||||
if id:
|
||||
model = S.query(model).get(id)
|
||||
if model:
|
||||
return model
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
def get_fieldset(self, id=None):
|
||||
"""return a ``FieldSet`` object bound to the correct record for ``id``.
|
||||
|
||||
Default is::
|
||||
|
||||
fs = self.FieldSet(self.get(id))
|
||||
fs.engine = fs.engine or self.engine
|
||||
return fs
|
||||
"""
|
||||
if self.forms and hasattr(self.forms, self.model_name):
|
||||
fs = getattr(self.forms, self.model_name)
|
||||
fs.engine = fs.engine or self.engine
|
||||
return id and fs.bind(self.get(id)) or fs
|
||||
fs = self.FieldSet(self.get(id))
|
||||
fs.engine = fs.engine or self.engine
|
||||
return fs
|
||||
|
||||
def get_add_fieldset(self):
|
||||
"""return a ``FieldSet`` used for add form.
|
||||
|
||||
Default is::
|
||||
|
||||
fs = self.get_fieldset()
|
||||
for field in fs.render_fields.itervalues():
|
||||
if field.is_readonly():
|
||||
del fs[field.name]
|
||||
return fs
|
||||
"""
|
||||
fs = self.get_fieldset()
|
||||
for field in fs.render_fields.itervalues():
|
||||
if field.is_readonly():
|
||||
del fs[field.name]
|
||||
return fs
|
||||
|
||||
def get_grid(self):
|
||||
"""return a Grid object
|
||||
|
||||
Default is::
|
||||
|
||||
grid = self.Grid(self.get_model())
|
||||
grid.engine = self.engine
|
||||
self.update_grid(grid)
|
||||
return grid
|
||||
"""
|
||||
model_name = self.model_name
|
||||
if self.forms and hasattr(self.forms, '%sGrid' % model_name):
|
||||
g = getattr(self.forms, '%sGrid' % model_name)
|
||||
g.engine = g.engine or self.engine
|
||||
g.readonly = True
|
||||
self.update_grid(g)
|
||||
return g
|
||||
grid = self.Grid(self.get_model())
|
||||
grid.engine = self.engine
|
||||
self.update_grid(grid)
|
||||
return grid
|
||||
|
||||
|
||||
def update_grid(self, grid):
|
||||
"""Add edit and delete buttons to ``Grid``"""
|
||||
try:
|
||||
grid.edit
|
||||
except AttributeError:
|
||||
def edit_link():
|
||||
return lambda item: '''
|
||||
<form action="%(url)s" method="GET" class="ui-grid-icon ui-widget-header ui-corner-all">
|
||||
<input type="submit" class="ui-grid-icon ui-icon ui-icon-pencil" title="%(label)s" value="%(label)s" />
|
||||
</form>
|
||||
''' % dict(url=self.route_url(self.model_name, _pk(item), 'edit'),
|
||||
label=get_translator().gettext('edit'))
|
||||
def delete_link():
|
||||
return lambda item: '''
|
||||
<form action="%(url)s" method="POST" class="ui-grid-icon ui-state-error ui-corner-all">
|
||||
<input type="submit" class="ui-icon ui-icon-circle-close" title="%(label)s" value="%(label)s" />
|
||||
</form>
|
||||
''' % dict(url=self.route_url(self.model_name, _pk(item), 'delete'),
|
||||
label=get_translator().gettext('delete'))
|
||||
grid.append(Field('edit', fatypes.String, edit_link()))
|
||||
grid.append(Field('delete', fatypes.String, delete_link()))
|
||||
grid.readonly = True
|
||||
|
||||
def listing(self, **kwargs):
|
||||
"""listing page"""
|
||||
page = self.get_page()
|
||||
fs = self.get_grid()
|
||||
fs = fs.bind(instances=page)
|
||||
fs.readonly = True
|
||||
if self.request.format == 'json':
|
||||
values = []
|
||||
request = self.request
|
||||
for item in page:
|
||||
pk = _pk(item)
|
||||
fs._set_active(item)
|
||||
value = dict(id=pk,
|
||||
item_url=self.route_url(request.model_name, pk))
|
||||
if 'jqgrid' in request.GET:
|
||||
fields = [_stringify(field.render_readonly()) for field in fs.render_fields.values()]
|
||||
value['cell'] = [pk] + fields
|
||||
else:
|
||||
value.update(dict([(field.key, field.model_value) for field in fs.render_fields.values()]))
|
||||
values.append(value)
|
||||
return self.render_json_format(rows=values,
|
||||
records=len(values),
|
||||
total=page.page_count,
|
||||
page=page.page)
|
||||
if 'pager' not in kwargs:
|
||||
pager = page.pager(**self.pager_args)
|
||||
else:
|
||||
pager = kwargs.pop('pager')
|
||||
return self.render_grid(fs=fs, id=None, pager=pager)
|
||||
|
||||
def create(self):
|
||||
"""REST api"""
|
||||
request = self.request
|
||||
S = self.Session()
|
||||
fs = self.get_add_fieldset()
|
||||
|
||||
if request.format == 'json' and request.method == 'PUT':
|
||||
data = json.load(request.body_file)
|
||||
else:
|
||||
data = request.POST
|
||||
|
||||
try:
|
||||
fs = fs.bind(data=data, session=S)
|
||||
except:
|
||||
# non SA forms
|
||||
fs = fs.bind(self.get_model(), data=data, session=S)
|
||||
if fs.validate():
|
||||
fs.sync()
|
||||
self.sync(fs)
|
||||
S.flush()
|
||||
if request.format == 'html':
|
||||
if request.is_xhr:
|
||||
response.content_type = 'text/plain'
|
||||
return ''
|
||||
return exc.HTTPFound(
|
||||
location=self.route_url(request.model_name))
|
||||
else:
|
||||
fs.rebind(fs.model, data=None)
|
||||
return self.render(fs=fs)
|
||||
return self.render(fs=fs, action='new', id=None)
|
||||
|
||||
def delete(self, **kwargs):
|
||||
"""REST api"""
|
||||
request = self.request
|
||||
id = request.model_id
|
||||
record = self.get(id)
|
||||
if record:
|
||||
S = self.Session()
|
||||
S.delete(record)
|
||||
if request.format == 'html':
|
||||
if request.is_xhr:
|
||||
response = Response()
|
||||
response.content_type = 'text/plain'
|
||||
return response
|
||||
return exc.HTTPFound(location=self.route_url(request.model_name))
|
||||
return self.render(id=id)
|
||||
|
||||
def show(self):
|
||||
"""REST api"""
|
||||
id = self.request.model_id
|
||||
fs = self.get_fieldset(id=id)
|
||||
fs.readonly = True
|
||||
return self.render(fs=fs, action='show', id=id)
|
||||
|
||||
def new(self, **kwargs):
|
||||
"""REST api"""
|
||||
fs = self.get_add_fieldset()
|
||||
fs = fs.bind(session=self.Session())
|
||||
return self.render(fs=fs, action='new', id=None)
|
||||
|
||||
def edit(self, id=None, **kwargs):
|
||||
"""REST api"""
|
||||
id = self.request.model_id
|
||||
fs = self.get_fieldset(id)
|
||||
return self.render(fs=fs, action='edit', id=id)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""REST api"""
|
||||
request = self.request
|
||||
S = self.Session()
|
||||
id = request.model_id
|
||||
fs = self.get_fieldset(id)
|
||||
if not request.POST:
|
||||
raise ValueError(request.POST)
|
||||
fs = fs.bind(data=request.POST)
|
||||
if fs.validate():
|
||||
fs.sync()
|
||||
self.sync(fs, id)
|
||||
S.flush()
|
||||
if request.format == 'html':
|
||||
if request.is_xhr:
|
||||
response.content_type = 'text/plain'
|
||||
return ''
|
||||
return exc.HTTPFound(
|
||||
location=self.route_url(request.model_name, _pk(fs.model)))
|
||||
else:
|
||||
return self.render(fs=fs, status=0)
|
||||
if request.format == 'html':
|
||||
return self.render(fs=fs, action='edit', id=id)
|
||||
else:
|
||||
return self.render(fs=fs, status=1)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
0.0
|
||||
---
|
||||
|
||||
- Initial version
|
||||
@@ -0,0 +1,4 @@
|
||||
pyramidapp README
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
[app:pyramidapp]
|
||||
use = egg:pyramidapp
|
||||
reload_templates = true
|
||||
debug_authorization = false
|
||||
debug_notfound = false
|
||||
debug_routematch = false
|
||||
debug_templates = true
|
||||
default_locale_name = en
|
||||
sqlalchemy.url = sqlite:///%(here)s/pyramidapp.db
|
||||
|
||||
[pipeline:main]
|
||||
pipeline =
|
||||
egg:WebError#evalerror
|
||||
egg:repoze.tm2#tm
|
||||
pyramidapp
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 6543
|
||||
|
||||
# Begin logging configuration
|
||||
|
||||
[loggers]
|
||||
keys = root, sqlalchemy
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
# "level = INFO" logs SQL queries.
|
||||
# "level = DEBUG" logs SQL queries and results.
|
||||
# "level = WARN" logs neither. (Recommended for production systems.)
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
|
||||
|
||||
# End logging configuration
|
||||
@@ -0,0 +1,25 @@
|
||||
from pyramid.config import Configurator
|
||||
from sqlalchemy import engine_from_config
|
||||
|
||||
from pyramidapp.models import initialize_sql
|
||||
|
||||
def main(global_config, **settings):
|
||||
""" This function returns a Pyramid WSGI application.
|
||||
"""
|
||||
engine = engine_from_config(settings, 'sqlalchemy.')
|
||||
initialize_sql(engine)
|
||||
config = Configurator(settings=settings)
|
||||
config.add_static_view('static', 'pyramidapp:static')
|
||||
config.add_route('home', '/', view='pyramidapp.views.my_view',
|
||||
view_renderer='templates/mytemplate.pt')
|
||||
config.load_zcml('pyramid_formalchemy:configure.zcml')
|
||||
config.add_route('fa_admin', '/admin/*traverse',
|
||||
factory='pyramid_formalchemy.resources.AdminView')
|
||||
config.registry.settings.update({
|
||||
'fa.models': config.maybe_dotted('pyramidapp.models'),
|
||||
'fa.forms': config.maybe_dotted('pyramidapp.forms'),
|
||||
'fa.session_factory': config.maybe_dotted('pyramidapp.models.DBSession'),
|
||||
})
|
||||
return config.make_wsgi_app()
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import transaction
|
||||
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy import Unicode
|
||||
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from sqlalchemy.orm import scoped_session
|
||||
from sqlalchemy.orm import 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(Unicode(255), unique=True)
|
||||
value = Column(Integer)
|
||||
|
||||
class Foo(Base):
|
||||
__tablename__ = 'foo'
|
||||
id = Column(Integer, primary_key=True)
|
||||
bar = Column(Unicode(255))
|
||||
|
||||
def populate():
|
||||
session = DBSession()
|
||||
model = MyModel(name=u'root',value=55)
|
||||
session.add(model)
|
||||
session.flush()
|
||||
for i in range(50):
|
||||
model = MyModel(name=u'root%i' % i,value=i)
|
||||
session.add(model)
|
||||
session.flush()
|
||||
transaction.commit()
|
||||
|
||||
def initialize_sql(engine):
|
||||
DBSession.configure(bind=engine)
|
||||
Base.metadata.bind = engine
|
||||
Base.metadata.create_all(engine)
|
||||
try:
|
||||
populate()
|
||||
except IntegrityError:
|
||||
DBSession.rollback()
|
||||
@@ -0,0 +1,3 @@
|
||||
class Root(object):
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 333 B |
|
After Width: | Height: | Size: 203 B |
@@ -0,0 +1,8 @@
|
||||
* html img,
|
||||
* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
|
||||
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
|
||||
this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
|
||||
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
|
||||
this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
|
||||
);}
|
||||
#wrap{display:table;height:100%}
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,65 @@
|
||||
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
|
||||
vertical-align:baseline;background:transparent;}
|
||||
body{line-height:1;}
|
||||
ol,ul{list-style:none;}
|
||||
blockquote,q{quotes:none;}
|
||||
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
|
||||
:focus{outline:0;}
|
||||
ins{text-decoration:none;}
|
||||
del{text-decoration:line-through;}
|
||||
table{border-collapse:collapse;border-spacing:0;}
|
||||
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
|
||||
sup{vertical-align:super;font-size:smaller;line-height:normal;}
|
||||
ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
|
||||
ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
|
||||
li{display:list-item;}
|
||||
ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
|
||||
ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
|
||||
ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
|
||||
.hidden{display:none;}
|
||||
p{line-height:1.5em;}
|
||||
h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
|
||||
h2{font-size:1.5em;line-height:1.7em;font-family:helvetica,verdana;}
|
||||
h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;}
|
||||
h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;}
|
||||
html,body{width:100%;height:100%;}
|
||||
body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
|
||||
a{color:#1b61d6;text-decoration:none;}
|
||||
a:hover{color:#e88f00;text-decoration:underline;}
|
||||
body h1,
|
||||
body h2,
|
||||
body h3,
|
||||
body h4,
|
||||
body h5,
|
||||
body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
|
||||
#wrap{min-height:100%;}
|
||||
#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
|
||||
#header{background:#000000;top:0;font-size:14px;}
|
||||
#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
|
||||
.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
|
||||
.wrapper{width:100%}
|
||||
#top,#top-small,#bottom{width:100%;}
|
||||
#top{color:#000000;height:230px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
|
||||
#top-small{color:#000000;height:60px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
|
||||
#bottom{color:#222;background-color:#ffffff;}
|
||||
.top,.top-small,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;}
|
||||
.top{padding-top:40px;}
|
||||
.top-small{padding-top:10px;}
|
||||
#middle{width:100%;height:100px;background:url(middlebg.png) repeat-x;border-top:2px solid #ffffff;border-bottom:2px solid #b2b2b2;}
|
||||
.app-welcome{margin-top:25px;}
|
||||
.app-name{color:#000000;font-weight:bold;}
|
||||
.bottom{padding-top:50px;}
|
||||
#left{width:350px;float:left;padding-right:25px;}
|
||||
#right{width:350px;float:right;padding-left:25px;}
|
||||
.align-left{text-align:left;}
|
||||
.align-right{text-align:right;}
|
||||
.align-center{text-align:center;}
|
||||
ul.links{margin:0;padding:0;}
|
||||
ul.links li{list-style-type:none;font-size:14px;}
|
||||
form{border-style:none;}
|
||||
fieldset{border-style:none;}
|
||||
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
|
||||
input[type=text],input[type=password]{width:205px;}
|
||||
input[type=submit]{background-color:#ddd;font-weight:bold;}
|
||||
/*Opera Fix*/
|
||||
body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 49 B |
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
|
||||
<head>
|
||||
<title>The Pyramid Web Application Development Framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
<meta name="keywords" content="python web application" />
|
||||
<meta name="description" content="pyramid web application" />
|
||||
<link rel="shortcut icon" href="${request.static_url('pyramidapp:static/favicon.ico')}" />
|
||||
<link rel="stylesheet" href="${request.static_url('pyramidapp:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
||||
<!--[if lte IE 6]>
|
||||
<link rel="stylesheet" href="${request.static_url('pyramidapp:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="top">
|
||||
<div class="top align-center">
|
||||
<div><img src="${request.static_url('pyramidapp:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="middle">
|
||||
<div class="middle align-center">
|
||||
<p class="app-welcome">
|
||||
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
|
||||
the Pyramid web application development framework.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bottom">
|
||||
<div class="bottom">
|
||||
<div id="left" class="align-right">
|
||||
<h2>Search documentation</h2>
|
||||
<form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
|
||||
<input type="text" id="q" name="q" value="" />
|
||||
<input type="submit" id="x" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="right" class="align-left">
|
||||
<h2>Pyramid links</h2>
|
||||
<ul class="links">
|
||||
<li>
|
||||
<a href="http://pylonshq.com">Pylons Website</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,103 @@
|
||||
import unittest
|
||||
from pyramid.config import Configurator
|
||||
from pyramid import testing
|
||||
|
||||
import os
|
||||
from webtest import TestApp
|
||||
from pyramidapp import main
|
||||
from paste.deploy import loadapp
|
||||
|
||||
dirname = os.path.abspath(__file__)
|
||||
dirname = os.path.dirname(dirname)
|
||||
dirname = os.path.dirname(dirname)
|
||||
|
||||
def _initTestingDB():
|
||||
from sqlalchemy import create_engine
|
||||
from pyramidapp.models import initialize_sql
|
||||
session = initialize_sql(create_engine('sqlite://'))
|
||||
return session
|
||||
|
||||
class TestController(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
app = loadapp('config:%s' % os.path.join(dirname, 'development.ini'))
|
||||
self.app = TestApp(app)
|
||||
self.config = Configurator(autocommit=True)
|
||||
self.config.begin()
|
||||
#_initTestingDB()
|
||||
|
||||
def tearDown(self):
|
||||
self.config.end()
|
||||
|
||||
|
||||
def test_index(self):
|
||||
# index
|
||||
resp = self.app.get('/admin/')
|
||||
resp.mustcontain('/admin/Foo')
|
||||
resp = resp.click('Foo')
|
||||
|
||||
## Simple model
|
||||
|
||||
# add page
|
||||
resp.mustcontain('/admin/Foo/new')
|
||||
resp = resp.click('New Foo')
|
||||
resp.mustcontain('/admin/Foo"')
|
||||
form = resp.forms[0]
|
||||
form['Foo--bar'] = 'value'
|
||||
resp = form.submit()
|
||||
assert resp.headers['location'] == 'http://localhost/admin/Foo', resp
|
||||
|
||||
# model index
|
||||
resp = resp.follow()
|
||||
resp.mustcontain('<td>value</td>')
|
||||
|
||||
# edit page
|
||||
form = resp.forms[0]
|
||||
resp = form.submit()
|
||||
form = resp.forms[0]
|
||||
form['Foo-1-bar'] = 'new value'
|
||||
#form['_method'] = 'PUT'
|
||||
resp = form.submit()
|
||||
resp = resp.follow()
|
||||
|
||||
# model index
|
||||
resp.mustcontain('<td>new value</td>')
|
||||
|
||||
# delete
|
||||
resp = self.app.get('/admin/Foo')
|
||||
resp.mustcontain('<td>new value</td>')
|
||||
resp = resp.forms[1].submit()
|
||||
resp = resp.follow()
|
||||
|
||||
assert 'new value' not in resp, resp
|
||||
|
||||
def test_json(self):
|
||||
# index
|
||||
response = self.app.get('/admin/json')
|
||||
response.mustcontain('{"models": {', '"Foo": "http://localhost/admin/Foo/json"')
|
||||
|
||||
## Simple model
|
||||
|
||||
# add page
|
||||
response = self.app.post('/admin/Foo/json',
|
||||
{'Foo--bar': 'value'})
|
||||
|
||||
data = response.json
|
||||
id = data['item_url'].split('/')[-1]
|
||||
|
||||
response.mustcontain('"Foo-%s-bar": "value"' % id)
|
||||
|
||||
|
||||
# get data
|
||||
response = self.app.get(str(data['item_url']))
|
||||
response.mustcontain('"Foo-%s-bar": "value"' % id)
|
||||
|
||||
# edit page
|
||||
response = self.app.post(str(data['item_url']), {'Foo-%s-bar' % id: 'new value'})
|
||||
response.mustcontain('"Foo-%s-bar": "new value"' % id)
|
||||
|
||||
# delete
|
||||
response = self.app.delete(str(data['item_url']))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
from pyramidapp.models import DBSession
|
||||
from pyramidapp.models import MyModel
|
||||
|
||||
def my_view(request):
|
||||
dbsession = DBSession()
|
||||
root = dbsession.query(MyModel).filter(MyModel.name==u'root').first()
|
||||
return {'root':root, 'project':'pyramidapp'}
|
||||
@@ -0,0 +1,27 @@
|
||||
[nosetests]
|
||||
match=^test
|
||||
nocapture=1
|
||||
cover-package=pyramidapp
|
||||
with-coverage=1
|
||||
cover-erase=1
|
||||
|
||||
[compile_catalog]
|
||||
directory = pyramidapp/locale
|
||||
domain = pyramidapp
|
||||
statistics = true
|
||||
|
||||
[extract_messages]
|
||||
add_comments = TRANSLATORS:
|
||||
output_file = pyramidapp/locale/pyramidapp.pot
|
||||
width = 80
|
||||
|
||||
[init_catalog]
|
||||
domain = pyramidapp
|
||||
input_file = pyramidapp/locale/pyramidapp.pot
|
||||
output_dir = pyramidapp/locale
|
||||
|
||||
[update_catalog]
|
||||
domain = pyramidapp
|
||||
input_file = pyramidapp/locale/pyramidapp.pot
|
||||
output_dir = pyramidapp/locale
|
||||
previous = true
|
||||
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
README = open(os.path.join(here, 'README.txt')).read()
|
||||
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
|
||||
|
||||
requires = [
|
||||
'pyramid',
|
||||
'SQLAlchemy',
|
||||
'transaction',
|
||||
'repoze.tm2',
|
||||
'zope.sqlalchemy',
|
||||
'WebError',
|
||||
]
|
||||
|
||||
if sys.version_info[:3] < (2,5,0):
|
||||
requires.append('pysqlite')
|
||||
|
||||
setup(name='pyramidapp',
|
||||
version='0.0',
|
||||
description='pyramidapp',
|
||||
long_description=README + '\n\n' + CHANGES,
|
||||
classifiers=[
|
||||
"Programming Language :: Python",
|
||||
"Framework :: Pylons",
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
|
||||
],
|
||||
author='',
|
||||
author_email='',
|
||||
url='',
|
||||
keywords='web wsgi bfg pylons pyramid',
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
test_suite='pyramidapp',
|
||||
install_requires = requires,
|
||||
entry_points = """\
|
||||
[paste.app_factory]
|
||||
main = pyramidapp:main
|
||||
""",
|
||||
paster_plugins=['pyramid'],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
[nosetests]
|
||||
match = ^test
|
||||
nocapture = 1
|
||||
cover-package = pyramidapp
|
||||
with-coverage = 1
|
||||
cover-erase = 1
|
||||
|
||||
[compile_catalog]
|
||||
directory = pyramid_formalchemy/locale
|
||||
domain = pyramid_formalchemy
|
||||
statistics = true
|
||||
|
||||
[extract_messages]
|
||||
add_comments = TRANSLATORS:
|
||||
output_file = pyramid_formalchemy/locale/pyramid_formalchemy.pot
|
||||
width = 80
|
||||
|
||||
[init_catalog]
|
||||
domain = pyramid_formalchemy
|
||||
input_file = pyramid_formalchemy/locale/pyramid_formalchemy.pot
|
||||
output_dir = pyramid_formalchemy/locale
|
||||
|
||||
[update_catalog]
|
||||
domain = pyramid_formalchemy
|
||||
input_file = pyramid_formalchemy/locale/pyramid_formalchemy.pot
|
||||
output_dir = pyramid_formalchemy/locale
|
||||
previous = true
|
||||
@@ -0,0 +1,30 @@
|
||||
import os
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
README = open(os.path.join(here, 'README.txt')).read()
|
||||
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
|
||||
|
||||
requires = ['pyramid', 'WebError', 'FormAlchemy']
|
||||
|
||||
setup(name='pyramid_formalchemy',
|
||||
version='0.0',
|
||||
description='pyramid_formalchemy',
|
||||
long_description=README + '\n\n' + CHANGES,
|
||||
classifiers=[
|
||||
"Programming Language :: Python",
|
||||
"Framework :: Pylons",
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
|
||||
],
|
||||
author='Gael Pasgrimaud',
|
||||
author_email='gael@gawel.org',
|
||||
url='',
|
||||
keywords='web pyramid pylons formalchemy',
|
||||
packages=find_packages(exclude=['pyramidapp']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=requires,
|
||||
)
|
||||
|
||||