Giter Site home page Giter Site logo

sandman's Introduction

This version is obsolete, please consider using https://github.com/jeffknupp/sandman2

Build Status

Coverage Status

Gitter chat

Analytics

PyPI

Discuss

Looking for a place to ask questions about sandman? Check out the sandman-discuss and sandman-users forums!

Documentation

Sandman documentation

sandman "makes things REST". Have an existing database you'd like to expose via a REST API? Normally, you'd have to write a ton of boilerplate code for the ORM you're using, then integrate that into some web framework.

I don't want to write boilerplate.

Here's what's required to create a RESTful API service from an existing database using sandman:

$ sandmanctl sqlite:////tmp/my_database.db

That's it. sandman will then do the following:

  • connect to your database and introspect its contents
  • create and launch a REST API service
  • create an HTML admin interface
  • open your browser to the admin interface

That's right. Given a legacy database, sandman not only gives you a REST API, it gives you a beautiful admin page and opens your browser to the admin page. It truly does everything for you.

Supported Databases

sandman, by default, supports connections to the same set of databases as SQLAlchemy. As of this writing, that includes:

  • MySQL (MariaDB)
  • PostgreSQL
  • SQLite
  • Oracle
  • Microsoft SQL Server
  • Firebird
  • Drizzle
  • Sybase
  • IBM DB2
  • SAP Sybase SQL Anywhere
  • MonetDB

Authentication

As of version 0.9.3, sandman fully supports HTTP Basic Authentication! See the documentation for more details.

Behind the Scenes

sandmanctl is really just a simple wrapper around the following:

from sandman import app

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///chinook'

from sandman.model import activate

activate()

app.run()

You don't even need to tell sandman what tables your database contains. Just point sandman at your database and let it do all the heavy lifting

Let's start our new service and make a request. While we're at it, lets make use of sandman's awesome filtering capability by specifying a filter term:

> python runserver.py &
* Running on http://127.0.0.1:5000/

> curl GET "http://localhost:5000/artists?Name=AC/DC"
...
{
    "resources": [
        {
            "ArtistId": 1,
            "Name": "AC/DC",
            "links": [
                {
                    "rel": "self",
                    "uri": "/artists/1"
                }
            ]
        }
    ]
}

All of that, including filtering/searching, is automagically available from those five measly lines of code.

Oh, that's not enough? You also want a Django-style admin interface built automatically? Fine. You may have noticed that when you ran runserver.py that a browser window popped up. Now's the time to go check that out. You'll find it's that Django-style admin interface you've been bugging me about, looking something like this:

admin interface awesomesauce screenshot


(If you want to disable the browser from opening automatically each time sandman starts, call activate with browser=False)

If you wanted to specify specific tables that sandman should make available, how do you do that? With this little ditty:

from sandman.model import register, Model

class Artist(Model):
    __tablename__ = 'Artist'

class Album(Model):
    __tablename__ = 'Album'

class Playlist(Model):
    __tablename__ = 'Playlist'

register((Artist, Album, Playlist))

And if you wanted to add custom logic for an endpoint? Or change the endpoint name? Or change your top level json object name? Or add validation? All supported. Here's a "fancy" class definition:

class Style(Model):
    """Model mapped to the "Genre" table

    Has a custom endpoint ("styles" rather than the default, "genres").
    Only supports HTTP methods specified.
    Has a custom validator for the GET method.

    """

    __tablename__ = 'Genre'
    __endpoint__ = 'styles'
    __methods__ = ('GET', 'DELETE')
    __top_level_json_name__ = 'Genres'

    @staticmethod
    def validate_GET(resource=None):
        """Return False if the request should not be processed.

        :param resource: resource related to current request
        :type resource: :class:`sandman.model.Model` or None

        """

        if isinstance(resource, list):
            return True
        elif resource and resource.GenreId == 1:
            return False
        return True

With sandman, zero boilerplate code is required. In fact, using sandmanctl, no code is required at all. Your existing database structure and schema is introspected and your database tables magically get a RESTful API and admin interface. For each table, sandman creates:

  • proper endpoints
  • support for a configurable set of HTTP verbs
    • GET
    • POST
    • PATCH
    • PUT
    • DELETE
  • responses with appropriate rel links automatically
    • foreign keys in your tables are represented by link
  • custom validation by simply defining validate_<METHOD> methods on your Model
  • explicitly list supported methods for a Model by setting the __methods__ attribute
  • customize a Models endpoint by setting the __endpoint__ method
  • essentially a HATEOAS-based service sitting in front of your database

sandman is under active development but should be usable in any environment due to one simple fact:

sandman never alters your database unless you add or change a record yourself. It adds no extra tables to your existing database and requires no changes to any of your existing tables. If you start sandman, use it to browse your database via cURL, then stop sandman, your database will be in exactly the same state as it was before you began.

Installation

pip install sandman

Example Application

Take a look in the sandman/test directory. The application found there makes use of the Chinook sample SQL database.

Contact Me

Questions or comments about sandman? Hit me up at [email protected].

Bitdeli Badge

Changelog

Version 0.9.8

  • Support for the wheel distribution format

Version 0.9.7

  • Slightly better test coverage and documentation

Version 0.9.6

  • Support for using existing declarative models alongside sandman generated models
    • If you have an existing app and want to include sandman in it, simply pass your existing models in to the register() function along with any sanmdman generated classes. sandman will detect the existing models and augment them.

Version 0.9.5

  • Fixes a critical bug where code used by the new etag decorators was accidentally not included. Thanks to @mietek for the PR.
  • Fixes an issue when showing the HTML representation of an empty collection.
  • Thanks to @mietek for reporting the issue.

Version 0.9.4

  • Fixes a critical bug in the requirements portion of setup.py, adding Flask-HTTPAuth

Version 0.9.3

  • Authentication supported!
    • Entire API and admin can be protected by HTTP Basic Auth. See the docs for more details.
  • ETAGs
    • Resources return the proper ETAG header and should reply with a 304 after the first request. This greatly improves the throughput and performance of the API.

Version 0.9.2

  • The meta endpoint
    • All resources now have a /<resource>/meta endpoint that describes the types of each of their fields (both in HTML and JSON)
  • The root endpoint
    • A "root" endpoint (/) has been created. It lists all resources registered in the application and includes URLs to their various endpoints. This allows a "dumb" client to navigate the API without knowing URLs beforehand.

Version 0.9.1

  • Python 3 support!
    • sandman tests now pass for both 2.7 and 3.4! Python 3.4 is officially supported.

Version 0.8.1

New Feature

  • Link header now set to a resource's links
    • Links to related objects now user a proper rel value: related
    • The link to the current resource still uses the self rel value
    • Links are specified both in the header (as per RFC5988) and in the resource itself
  • Pagination added for JSON (and number of results per page being returned is fixed)
  • Nested JSON models no longer the default; hitting a URL with the argument "expand" will show one level of nested resources
    • This conforms more closely to REST principles while not sacrificing the functionality.

Version 0.7.8

Bug Fixes

  • Fix multiple references to same table error (fixes #59)

sandman's People

Contributors

areski avatar darengit avatar dolinsky avatar durden avatar flokli avatar ir4y avatar ishaan avatar jeffknupp avatar mietek avatar shlomif avatar tinche avatar valhallasw avatar zevaverbach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sandman's Issues

Error using sandman on OpenERP 7 postgresql database

trying to use sandman on a OpenERP 7 postgresql database
I get following output

/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/reflection.py:49: SAWarning: Skipped unsupported reflection of expression-based index res_currency_unique_name_company_id_idx
ret = fn(self, con, _args, *_kw)
/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/reflection.py:49: SAWarning: Skipped unsupported reflection of expression-based index ir_filters_name_model_uid_unique_index
ret = fn(self, con, _args, *_kw)
Traceback (most recent call last):
File "/usr/local/bin/sandmanctl", line 52, in
sys.exit(main())
File "/usr/local/bin/sandmanctl", line 48, in main
activate(admin=True)
File "/usr/local/lib/python2.7/dist-packages/sandman/model/init.py", line 78, in activate
{'tablename': name})
File "/usr/local/lib/python2.7/dist-packages/flask_sqlalchemy/init.py", line 510, in init
DeclarativeMeta.init(self, name, bases, d)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative/api.py", line 50, in init
_as_declarative(cls, classname, cls.dict)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative/base.py", line 292, in as_declarative
mt.map()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative/base.py", line 376, in map
**mapper_args
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/init.py", line 1229, in mapper
return Mapper(class
, local_table, _args, *_params)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/mapper.py", line 221, in init
self._configure_pks()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/mapper.py", line 824, in _configure_pks
(self, self.mapped_table.description))
sqlalchemy.exc.ArgumentError: Mapper Mapper|account_bank_statement_line_move_rel|account_bank_statement_line_move_rel could not assemble any primary key columns for mapped table 'account_bank_statement_line_move_rel'

Allow using sandman as a blueprint rather than an app

It would be useful to have sandman optionally usable as a Blueprint.

As it is right now, sandman works well if all you want is a REST API, but it's difficult and/or impossible to add a REST API to an existing app without hacking your app on top of the app sandman automatically builds.

It should be possible to just do something like:

from flask import Flask
from sandman import blueprint as sandman_blueprint

app = Flask(__name__)
app.register_blueprint(sandman_blueprint, url_prefix='/api')
app.register_resource((Model, OtherModel))

Or I suppose instead of adding a method to the app object, there could just be an optional app argument to sandman.register.

Basically, I'm saying sandman should be able to function without using any global shared objects. That goes for the db global as well. One of the nice things about Flask is that it does away with all the "magic globals" that so many other frameworks have, so it'd be nice to preserve that with sandman which otherwise seems like a very nice library!

Foreign key relationships and table and class naming

A tables with foreign key relationship to a second table causes a crash (KeyError) if class name != table name. Work around is to name class exactly the same as the table.

E.g. my program cadmini.py has

class Edcs(Model):
    __tablename__ = 'edcs'

for error

Traceback (most recent call last):
File "./cadmini.py", line 74, in
activate_admin_classes()
File "/usr/local/lib/python2.7/dist-packages/sandman/model/init.py", line 59, in activate_admin_classes
_prepare_relationships()
File "/usr/local/lib/python2.7/dist-packages/sandman/model/init.py", line 50, in _prepare_relationships
other = current_app.classes_by_name[foreign_key['referred_table']]
KeyError: u'edcs'

sqlalchemy.exc.NoSuchTableError: sandman with basic example

I started with real databases until creating a very simple database with one table, two fields, and always same error.

I am registering and not registering the table.

from sandman.model import register, activate, Model

class Banner(Model):
    __tablename__ = 'sandman'

register(Banner)
activate(admin=True)

from sandman import app, db

app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:xxx@localhost/mydb'
app.run()

Error trace:

Traceback (most recent call last):
  File "hoya.py", line 7, in <module>
    activate(admin=True)
  File "/usr/local/lib/python2.7/dist-packages/sandman/model/__init__.py", line 78, in activate
    Model.prepare(db.engine)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative/api.py", line 470, in prepare
    cls._sa_decl_prepare(thingy.local_table, engine)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative/api.py", line 486, in _sa_decl_prepare
    schema=local_table.schema)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/schema.py", line 322, in __new__
    table._init_existing(*args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/schema.py", line 465, in _init_existing
    self.metadata, autoload_with, include_columns, exclude_columns)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/schema.py", line 413, in _autoload
    self, include_columns, exclude_columns
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1595, in run_callable
    return conn.run_callable(callable_, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1118, in run_callable
    return callable_(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 262, in reflecttable
    return insp.reflecttable(table, include_columns, exclude_columns)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/reflection.py", line 461, in reflecttable
    raise exc.NoSuchTableError(table.name)
sqlalchemy.exc.NoSuchTableError: sandman

Debian 7, python 2.7, Maria Db 5.x

I feel a bit dumb for not being able to run the simplest setup, if there is anything else I can provide please tell me.

Thanks

How to connect to mysql/postgres

Love this app, but the documentation isn't clear on how to connect to a db like MySQL or Postgres. I'm guessing I need to hunt through the code to find it?

Cannot map to database table without a primary key.

I get this error when trying to map to a ms sql server table without any primary keys.
sqlalchemy.exc.ArgumentError: Mapper Mapper could not assemble any primary key columns for mapped table

Full Trace
Traceback (most recent call last):
File "c:/Python27/Scripts/sandmanctl", line 52, in
sys.exit(main())
File "c:/Python27/Scripts/sandmanctl", line 48, in main
activate(admin=True)
File "C:\Python27\lib\site-packages\sandman\model__init__.py", line 78, in activate
{'tablename': name})
File "C:\Python27\lib\site-packages\flask_sqlalchemy__init__.py", line 510, in init
DeclarativeMeta.init(self, name, bases, d)
File "C:\Python27\lib\site-packages\sqlalchemy\ext\declarative\api.py", line 50, in init
as_declarative(cls, classname, cls.dict)
File "C:\Python27\lib\site-packages\sqlalchemy\ext\declarative\base.py", line 292, in as_declarative
mt.map()
File "C:\Python27\lib\site-packages\sqlalchemy\ext\declarative\base.py", line 376, in map
**mapper_args
File "C:\Python27\lib\site-packages\sqlalchemy\orm__init
.py", line 1229, in mapper
return Mapper(class_, local_table, _args, *_params)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 221, in init
self._configure_pks()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 824, in _configure_pks
(self, self.mapped_table.description))
sqlalchemy.exc.ArgumentError: Mapper Mapper|Group_Subgroup_Contact|Group_Subgroup_Contact could not assemble any primary key columns for mapped table 'Group_Subgroup_Contact'

It would be nice to have a way to specify what column should map as primary key or allow none.

can sandman work with one table and build nested routes?

for example I have one table as so. I would like to build a tree out of it and store it in sandman so that it can give me routes like

cat1/subcats/subcats/data, cat3/subcats/data

the table

cat1|subcat|subcat|data
cat1|subcat2|subcat|data
cat2|subcat|data
cat3|subcat|data
cat3|subcat2|data
cat3|subcat3|data

any suggestions would be great.

Plurals are computed incorrectly in resources vs urls

If a table is already plural (such as a table named 'tasks') then I can go to the name of the table localhost:5000/tasks and get a list of items in the table. However, the URL for a single item is returned as /taskss/1 and following that link does not work. I have to take off the extra S at the end for that link to work.

Blueprint collision error

Output of sandmanctl --all-columns-primary sqlite:////Users/jan/main.db:

/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/ext/declarative/clsregistry.py:159: SAWarning: This declarative base already contains a class with the same class name and module name as flask_sqlalchemy.Chats, and will be replaced in the string-lookup table.
  existing.add_item(cls)
sandmanctl
Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/foo/bin/sandmanctl", line 9, in <module>
    load_entry_point('sandman==0.7.0', 'console_scripts', 'sandmanctl')()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/sandmanctl.py", line 58, in main
    activate(name='sandmanctl')
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/model/utils.py", line 155, in activate
    name)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/model/utils.py", line 130, in register_classes_for_admin
    admin_view.add_view(admin_view_class(cls, db_session))
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 495, in add_view
    self.app.register_blueprint(view.create_blueprint(self))
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 62, in wrapper_func
    return f(self, *args, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 885, in register_blueprint
    (blueprint, self.blueprints[blueprint.name], blueprint.name)
AssertionError: A blueprint's name collision occurred between <flask.blueprints.Blueprint object at 0x10af96610> and <flask.blueprints.Blueprint object at 0x10aef2390>.  Both share the same name "chatsview".  Blueprints that are created on the fly need unique names.

Consider merging with armet

This looks like a great project you have here @jeffknupp.

I'd like you to take a look at https://github.com/armet/python-armet and for you to consider merging our efforts.

There isn't a lot of documentation for it at the moment (looking to rectify that very shortly) but here is the general idea. Armet is a RESTful abstraction framework that plugs in to anything (eg. django, tornado, sqlalchemy, bottle, flask, etc.). A basic example below. We've got a good bit of features like authentication, authorization, advanced filtering, etc.

from armet import resources
from . import models, app

@armet.route('/', app)
class Album(resources.ModelResource):
    class Meta:
        connectors = {'http': 'flask', 'model': 'sqlalchemy'}
        model = models.Album
        slug = resources.IntegerAttribute('id')

    id = resources.IntegerAttribute('id')
    name = resources.TextAttribute('name')

That would allow a various requests to /album (eg. POST, PUT, OPTIONS, etc.)

Something you're doing currently that I've had plans to add to armet is the attribute detection.


Both of our projects are still fairly new and malleable so what I am proposing is we work together to add all the features from sandman you'd want, closing sandman, and then jointly maintaining armet (the primary reason for sandman into armet is that armet has the connector structure in-place to support most frameworks) and making it the best possible RESTful framework we can.

What do you think?

Error template not found

When rendering an error, the console outputs:

Traceback (most recent call last):
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/app.py", line 1379, in handle_user_exception
    return handler(e)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/sandman/sandman.py", line 64, in handle_exception
    return error.abort()
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/sandman/exception.py", line 24, in abort
    resp = make_response(render_template('error.html', error=self.code, message=self.message), self.code)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/templating.py", line 127, in render_template
    return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/jinja2/environment.py", line 830, in get_or_select_template
    return self.get_template(template_name_or_list, parent, globals)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/jinja2/environment.py", line 791, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/jinja2/environment.py", line 765, in _load_template
    template = self.loader.load(self, name, globals)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/jinja2/loaders.py", line 113, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "/home/stapled/python_envs/ansible/lib/python2.7/site-packages/flask/templating.py", line 64, in get_source
    raise TemplateNotFound(template)
TemplateNotFound: error.html

Note - the admin template and interface appears to be fine - so it doesn't look like all templates are missing.
I attempted to query something directly in the browser (as opposed to curl).

Environment information:

$ pip freeze
Flask==0.10.1
Flask-Admin==1.0.7
Flask-SQLAlchemy==1.0
Jinja2==2.7.1
MarkupSafe==0.18
PyYAML==3.10
SQLAlchemy==0.9.1
WTForms==1.0.5
Werkzeug==0.9.4
ansible==1.4.1
docopt==0.6.1
ecdsa==0.10
itsdangerous==0.23
paramiko==1.12.0
pycrypto==2.6.1
sandman==0.7.5
wsgiref==0.1.2

$ python --version
Python 2.7.5

$ lsb_release -a
LSB Version:    :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
Distributor ID: Fedora
Description:    Fedora release 19 (Schrödinger’s Cat)
Release:    19
Codename:   Schrödinger’sCat

Always get "sqlalchemy.exc.AmbiguousForeignKeysError"

I was excited to learn about Sandman and was hoping it would Just Work when pointed at the MySQL databases used by OpenStack. Unfortunately, for every database I've tried I get:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship floatingips.ports - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

IOError running sandmanctl

This is against aba5993.

I have sandman installed into a python virtualenv.

I ran sandmanctl against a local database:

sandmanctl --port=7070 mysql://USER:[email protected]/keystone

This resulted in:

IOError: [Errno 20] Not a directory: '/home/lars/env/common/lib/python2.7/site-packages/sandman-0.7.4-py2.7.egg/sandman/templates/admin/index.html'

UnicodeDecodeError when handling certain row values

When clicking on the table name in the admin header:

Traceback:

Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 60, in inner
    return f(self, *args, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 60, in inner
    return f(self, *args, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/model/base.py", line 1182, in index_view
    actions_confirmation=actions_confirmation)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 254, in render
    return render_template(template, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/templating.py", line 128, in render_template
    context, ctx.app)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/templating.py", line 110, in _render
    rv = template.render(context)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/model/list.html", line 4, in top-level template code
    {% import 'admin/actions.html' as actionlib with context %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/master.html", line 1, in top-level template code
    {% extends admin_base_template %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/base.html", line 22, in top-level template code
    {% block page_body %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/base.html", line 50, in block "page_body"
    {% block body %}{% endblock %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/model/list.html", line 49, in block "body"
    {% block model_list_table %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/model/list.html", line 95, in block "model_list_table"
    {% block list_row scoped %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/model/list.html", line 118, in block "list_row"
    <td>{{ get_value(row, c) }}</td>
UnicodeDecodeError: 'ascii' codec can't decode byte 0x8f in position 2: ordinal not in range(128)

Having a look at the value using the Werkzeug debugger:

c
u'chatmsg_guid'
row.chatmsg_guid
'Qc\x8f0;\xd3\xb9\xac\xd8\xc8\x11S\xc4\xb5\xed9"Q\xf21\x19#\x9a\xd0@[\xa2zH\xe4Y\xe4'

So, it's really a binary value that's not to be decoded in this case. Maybe just catch the exception and spit back the string's repr() if it can't be decoded?

Can't easily set BaseModelView.<some class field>

There are a lot of class fields in BaseModelView that govern the behavior of the flask-admin. While using sandman its not straight forward how we can set any of BaseModelView's class fields. It would be great if we can do something like this:

""" assume a table called 'new_job' with primary key 'name' """

class new_job(Model):
tablename = 'new_job'

class new_jobAdminView(ModelView):
column_display_pk = True
column_searchable_list = ('name')

register(new_job)
activate_admin_classes(new_jobAdminView)

Wildcard

Add the ability to use a wildcard in a query, kinda like the LIKE in SQL.

curl -v -X GET http://127.0.0.1/artist?name=%AC%

Returning message NULL

Everything seems to be alright (testing with a single table just like the tutorial at README) but when i call the the url a strange return;

curl localhost:5000/coupon

{
"message": null
},

but when i run with admin access, the issue appeared:

sqlalchemy.exc.ArgumentError: status._ref_status and back-reference status._fk_status are both of the same direction <symbol 'ONETOMANY>. Did you mean to set remote_side on the many-to-one side ?

This is a table, that have a reference to other table, and a self reference. So in Alchemy we need to set parameter remote_side, but how i do that in sandman ?

Relative path creates an empty database

When using SQLite relative path creates an empty database in sandman directory in site-packages.

Running sandmanctl "sqlite:///test.db" in the same directory as test.db creates an empty database by that name in sandmans directory in site-packages.
Using the full path it works normally.

Error trying to use sandmanctl with sqlite3 database supplied via relative path

$ ls -l History
-rw-r--r-- 1 jan staff 5906432 Dec 26 00:38 History
$ sandmanctl --all-columns-primary sqlite:///History
Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/foo/bin/sandmanctl", line 9, in <module>
    load_entry_point('sandman==0.7.0', 'console_scripts', 'sandmanctl')()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/sandmanctl.py", line 58, in main
    activate(name='sandmanctl')
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/model/utils.py", line 150, in activate
    prepare_relationships(current_app)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/model/utils.py", line 60, in prepare_relationships
    for cls in current_app.classes:
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: 'Flask' object has no attribute 'classes'

(Using sqlite:////absolute/path/to/History "works" (see other bugs submitted))

setup.py should not import the thing it's installing

This creates major chicken-and-egg problems at install time. Works for you because you've already got all your dependencies...

[23:13:14]Pauls-MacBook-Air ~:(trunk)$ virtualenv --no-site-packages test2
New python executable in test2/bin/python
Installing setuptools............done.
Installing pip...............done.
[23:13:20]Pauls-MacBook-Air ~:(trunk)$ cd test2
[23:13:23]Pauls-MacBook-Air test2:$ source bin/activate
(test2)[23:13:26]Pauls-MacBook-Air test2:$ pip install sandman
Downloading/unpacking sandman
  Using download cache from /Users/pw/tmp/pip-download-cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2Fsource%2Fs%2Fsandman%2Fsandman-0.4.0.tar.gz
  Running setup.py egg_info for package sandman
    Traceback (most recent call last):
      File "<string>", line 16, in <module>
      File "/Users/pw/test2/build/sandman/setup.py", line 8, in <module>
        import sandman
      File "sandman/__init__.py", line 7, in <module>
        from flask import Flask
    ImportError: No module named flask
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 16, in <module>

  File "/Users/pw/test2/build/sandman/setup.py", line 8, in <module>

    import sandman

  File "sandman/__init__.py", line 7, in <module>

    from flask import Flask

ImportError: No module named flask

----------------------------------------
Command python setup.py egg_info failed with error code 1 in /Users/pw/test2/build/sandman
Storing complete log in /Users/pw/.pip/pip.log

admin-ui can not edit primary key

We can get the admin-ui to display the primary key, however we can not edit it. Not sure if this is an appropriate issue or a "feature"

sandmanctl conflicts with anything else using port 5000

I tried running sandmanctl and received:

socket.error: [Errno 98] Address already in use

I looked but I can't find any way to specify an alternate port. Looking through the code it looks like this port is currently hardcoded, e.g., in sandman/samdna.py:

response.headers['Location'] = 'http://localhost:5000/{}'.format(
        resource.resource_uri())

Bootstrap Error on loading admin

Output of sandmanctl --all-columns-primary sqlite:////Users/jan/History:

/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'current_path'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'target_path'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'url'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'lower_term'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'term'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'key'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'value'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'title'
  default, primary_key))
sandmanctl
 * Running on http://0.0.0.0:5000/
 * Restarting with reloader
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'current_path'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'target_path'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'url'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'lower_term'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'term'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'key'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'value'
  default, primary_key))
/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py:808: SAWarning: Did not recognize type 'LONGVARCHAR' of column 'title'
  default, primary_key))
sandmanctl
127.0.0.1 - - [03/Jan/2014 15:43:01] "GET /admin HTTP/1.1" 301 -
127.0.0.1 - - [03/Jan/2014 15:43:01] "GET /admin/ HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 60, in inner
    return f(self, *args, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 344, in index
    return self.render(self._template)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/base.py", line 254, in render
    return render_template(template, **kwargs)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/templating.py", line 128, in render_template
    context, ctx.app)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/templating.py", line 110, in _render
    rv = template.render(context)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/index.html", line 1, in top-level template code
    {% extends 'admin/master.html' %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/master.html", line 1, in top-level template code
    {% extends admin_base_template %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/base.html", line 11, in top-level template code
    {% block head_css %}
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_admin/templates/admin/base.html", line 12, in block "head_css"
    <link href="{{ url_for('admin.static', filename='bootstrap/css/bootstrap.css') }}" rel="stylesheet">
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/helpers.py", line 312, in url_for
    return appctx.app.handle_url_build_error(error, endpoint, values)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/app.py", line 1641, in handle_url_build_error
    reraise(exc_type, exc_value, tb)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask/helpers.py", line 305, in url_for
    force_external=external)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/werkzeug/routing.py", line 1620, in build
    raise BuildError(endpoint, values, method)
BuildError: ('admin.static', {'filename': 'bootstrap/css/bootstrap.css'}, None)

foreign key causing weird behavior

Using mysql connector python to connect to mysql we have a table (job_schedule) with the following foreign key constraint:

CONSTRAINT js_fk_data_source FOREIGN KEY (data_source) REFERENCES data_sources (name)

note that job_schedule.data_source is constrained to data_sources.name, but job_schedule.name does not exist. In this case when we attempt to access /job_schedules using sandman we get this error:

Traceback (most recent call last):
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1836, in call
return self.wsgi_app(environ, start_response)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/dzou/sandman_env/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/home/dzou/sandman_env/lib/python2.7/site-packages/sandman/sandman.py", line 388, in get_collection
return collection_response(resources)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/sandman/sandman.py", line 220, in collection_response
return _collection_json_response(resources)
File "/home/dzou/sandman_env/lib/python2.7/site-packages/sandman/sandman.py", line 100, in _collection_json_response
result_list.append(resource.as_dict())
File "/home/dzou/sandman_env/lib/python2.7/site-packages/sandman/model/models.py", line 96, in as_dict
result_dict['links'] = self.links()
File "/home/dzou/sandman_env/lib/python2.7/site-packages/sandman/model/models.py", line 70, in links
links.append({'rel': endpoint, 'uri': '/{}/{}'.format(endpoint, getattr(self, column))})
AttributeError: 'job_schedule' object has no attribute 'name'

datetime.date(2008, 5, 27) is not JSON serializable

I get this error while requesting a list of resources:

´´´
127.0.0.1 - - [23/Dec/2013 14:11:58] "GET /entities HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in call
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 397, in get_collection
return collection_response(resources)
File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 228, in collection_response
return _collection_json_response(resources)
File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 101, in _collection_json_response
return jsonify(resources=result_list)
File "/usr/local/lib/python2.7/dist-packages/flask/json.py", line 238, in jsonify
indent=indent),
File "/usr/local/lib/python2.7/dist-packages/flask/json.py", line 126, in dumps
rv = _json.dumps(obj, **kwargs)
File "/usr/share/pyshared/simplejson/init.py", line 334, in dumps
**kw).encode(obj)
File "/usr/share/pyshared/simplejson/encoder.py", line 239, in encode
chunks = list(chunks)
File "/usr/share/pyshared/simplejson/encoder.py", line 551, in _iterencode
for chunk in _iterencode_dict(o, _current_indent_level):
File "/usr/share/pyshared/simplejson/encoder.py", line 514, in _iterencode_dict
for chunk in chunks:
File "/usr/share/pyshared/simplejson/encoder.py", line 422, in _iterencode_list
for chunk in chunks:
File "/usr/share/pyshared/simplejson/encoder.py", line 514, in _iterencode_dict
for chunk in chunks:
File "/usr/share/pyshared/simplejson/encoder.py", line 561, in _iterencode
o = _default(o)
File "/usr/local/lib/python2.7/dist-packages/flask/json.py", line 83, in default
return _json.JSONEncoder.default(self, o)
File "/usr/share/pyshared/simplejson/encoder.py", line 213, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.date(2008, 5, 27) is not JSON serializable
´´´

Database field is of datetime type.
Listing an editing through admin interface works ok.

Cheers.

Does not work with Subclasses

I have an existing Flask app that subclasses Model. I have modified it to use sandman.

class Foo(Model):

class Bar(Foo):

but I receive an error at the second class definition.

sqlalchemy.exc.InvalidRequestError: Table 'foo' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

This works fine in my regular Flask app, so I think it may be a bug with sandman.

new sandmanctl error after upgrading to 0.7.1

pretty sure this just showed me the needed options in 0.7

$ sandmanctl
Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/foo/bin/sandmanctl", line 52, in <module>
    sys.exit(main())
  File "/Users/jan/.virtualenvs/foo/bin/sandmanctl", line 48, in main
    activate(admin=True)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/sandman/model/__init__.py", line 70, in activate
    db.metadata.reflect(bind=db.engine)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 780, in engine
    return self.get_engine(self.get_app())
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 797, in get_engine
    return connector.get_engine()
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 470, in get_engine
    self._sa.apply_driver_hacks(self._app, info, options)
  File "/Users/jan/.virtualenvs/foo/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 739, in apply_driver_hacks
    if info.drivername.startswith('mysql'):
AttributeError: 'NoneType' object has no attribute 'drivername'

Join condition for many foreign key

I have relation at my database like this:

class Customer(Base):
    __tablename__ = 'customer'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    billing_address_id = Column(Integer, ForeignKey("address.id"))
    shipping_address_id = Column(Integer, ForeignKey("address.id"))

  billing_address = relationship("Address", foreign_keys=[billing_address_id])
  shipping_address = relationship("Address", foreign_keys=[shipping_address_id])

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    street = Column(String)
    city = Column(String)
    state = Column(String)

When sandman try to create models from database, i get the error:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables

Error after long idle

When sandman idles without a connection for a time period, I get a MySQL server has gone away error message

95.91.245.42 - - [07/Jan/2014 21:04:14] "GET /artists?name='AC/DC' HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 469, in get_collection
    return collection_response(resources, start, stop)
  File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 261, in collection_response
    return _collection_json_response(resources)
  File "/usr/local/lib/python2.7/dist-packages/sandman/sandman.py", line 127, in _collection_json_response
    for resource in resources:
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2392, in __iter__
    return self._execute_and_instances(context)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2407, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 664, in execute
    return meth(self, multiparams, params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/elements.py", line 282, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 761, in _execute_clauseelement
    compiled_sql, distilled_params
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 874, in _execute_context
    context)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1023, in _handle_dbapi_exception
    exc_info
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/compat.py", line 185, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 867, in _execute_context
    context)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 388, in do_execute
    cursor.execute(statement, parameters)
  File "/usr/share/pyshared/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/share/pyshared/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
OperationalError: (OperationalError) (2006, 'MySQL server has gone away') ('SELECT [...]')

Error trying to access Skype DB

Trying to open Skype main.db:

Traceback (most recent call last):
  File "/Users/jan/.virtualenvs/sandman/bin/sandmanctl", line 52, in <module>
    sys.exit(main())
  File "/Users/jan/.virtualenvs/sandman/bin/sandmanctl", line 48, in main
    activate(admin=True)
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sandman/model/__init__.py", line 78, in activate
    {'__tablename__': name})
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 510, in __init__
    DeclarativeMeta.__init__(self, name, bases, d)
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 50, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 292, in _as_declarative
    mt.map()
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 376, in map
    **mapper_args
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/orm/__init__.py", line 1229, in mapper
    return Mapper(class_, local_table, *args, **params)
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 221, in __init__
    self._configure_pks()
  File "/Users/jan/.virtualenvs/sandman/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 824, in _configure_pks
    (self, self.mapped_table.description))
sqlalchemy.exc.ArgumentError: Mapper Mapper|AppSchemaVersion|AppSchemaVersion could not assemble any primary key columns for mapped table 'AppSchemaVersion'

skip tables with missing primary keys

looks like sqlalchemy doesn't work with tables without a primary key:
sqlalchemy.exc.ArgumentError: Mapper Mapper|sap_zpp_bom_report|sap_zpp_bom_report could not assemble any primary key columns for mapped table 'sap_zpp_bom_report'

using:
sandman==0.7.5
SQLAlchemy==0.9.1
Flask-SQLAlchemy==1.0

add docs for the new __view__ attribute

Reference: #41

Any chance we can get something added to the docs for this? I'm not sure I understand how to use this attribute. I've tried making a model view based on Flask-Admin's BaseView class, and making that available to my model:

from sandman.model import Model
from flask.ext.admin import BaseView, expose

class FooView(BaseView):
@expose('/')
    def index(self):
        return self.render('index.html')

class Foo(Model):
    __tablename__ = 'foo'
    __view__ = FooView

The next result is a dropdown menu on my navbar which says '<sqlalchemy.orm.scoped_session object at 0x.....> with a submenu item which says <class 'models.Foo'> ... and clicking on it throws a 500 error for a TemplateNotFound (index.html) exception.

MS SQL Server Support: Cannot Paginate

Trying to go through the pagination (Page 2 on any table) the following error is reported:

CompileError: MSSQL requires an order_by when using an offset.

Note that if you first sort by a column and try it again, it works fine.

Add script for simple startup

I'm thinking Sandman might be very interesting for integration testing at my work place.

Reading your docs, for very simple usage only a single piece of information is needed: the SQLAlchemy connection string. So why not bundle a simple CLI client (say, 'sandman') that would take a few parameters as command line args and eliminate all Python boilerplate, at least for simple use cases?

For example, I'd like to be able to install sandman and just do

sandman postgresql://user:pass@localhost:5432/database

and have my database exposed for use by my test runner. Also interesting would be a parameter to have the server bind to other/all interfaces, instead of only localhost.

I might be persuaded to contribute this if you agree it would be useful. :)

case sensitivity

Tables are case sensitive with mssql and pyodbc. It should be case insensitive. URLs generated are all in lowercase, but using those do not work. Either you need to make this case sensitive ( and generate case sensitive URLs ) or you need to make it all case insensitive (and make the DB calls case insensitive as well ).

Doesn't work with Python 2.6

The reason are the formatted strings: in Python 2.7+, "Your name is {}".format(name) is allowed, while 2.6 requires a position argument "Your name is {0}".format(name).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.