[three]Bean

(most) all tw2 widgets have samples!

Apr 28, 2011 | categories: python, toscawidgets View Comments

I just got two requests for a tutorial on tw2.jqplugins.jqgrid.SQLAjqGridWidget which interrogates whatever sqlalchemy model you give it and produces a nifty jqgrid web widget (python, WSGI, of course!)

Before I release a tutorial, I thought I'd point out that (most) all tw2 widgets have a tw2..samples module which:

  • 1) Gets picked up and rendered by the tw2.devtools widget browser (which is running live here).
  • 2) Can educate you on how to use the widgets in which you are particularly interested.

For the SQLAjqGridWidget, you can find that code right here on my github account.

Tutorial coming soon!

View Comments

jquery-ui portlets with saved position and state via cookies

Apr 25, 2011 | categories: python, toscawidgets, javascript View Comments

Back in June of 2010, I was wondering how to save the order/arrangement of jquery-ui portlets and their open/closed state to a cookie. After much searching and finding nothing, I came up with my own solution and posted it at the end of a long thread on the jquery-ui mailing list. (Since then, I found that it's been linked to from a stackoverflow answer!)

You can see a live demo of my solution here.

If you're a python web programmer, you should know that my tw2.jqplugins.portlets package uses this solution by default, encapsulating all the work for you. Here are links to everything you need to get started using that project:

View Comments

SQLARadialGraph in a Pyramid app

Mar 07, 2011 | categories: python, toscawidgets, pyramid View Comments

tw2.jit.SQLARadialGraph is a python class that encapsulates the awesome RGraph widget from the Javascript InfoVis Toolkit and automatically sets it up with JSON data from a sqlalchemy-mapped database. This post is a tutorial on how to make use of it in an application built on the Pyramid web framework.

1. Create a fresh pyramid app from the pyramid_alchemy paster template (instructions).

2. Create some sqlalchemy models with one-to-many and/or many-to-many relationships and populate the DB along the lines described in my SQLARadialGraph in a Turbogears 2.1 app tutorial.

3. Include tw2.jit and formencode in the requires list in your setup.py file and re-run python setup.py develop with your virtualenv active.

4. Include the Toscawidgets 2 middleware in the Pyramid WSGI stack by specifying egg:tw2.core#middleware just before your application's line in the pipeline setting inside development.ini.

5. Create a module /widgets.py with the following contents:

from tw2jitpyramiddemo import models
from tw2.jit import SQLARadialGraph

class UserGraph(SQLARadialGraph):
    id = 'whatever'
    base_url = '/jit_data'
    entities = [models.MyModel, models.MyGroup]
    width = '750'
    height = '533'

6. Expose the UserGraph widget in one of your views.

Specifically, modify /views.py and change the view_model(context, request) view to look something like:

from widgets import UserGraph

def view_model(context, request):
    return {'item':context, 'project':'tw2.jit-pyramid-demo',
            'jitwidget':UserGraph(rootObject=context)}

7. Render the widget in the corresponding template.

If you're using Chameleon templates (/templates/model.pt) this looks like:

<div tal:content="structure jitwidget.display()"></div>

If you're using Mako templates (/templates/model.mak) this looks like:

${jitwidget.display() | n}

8. Open a route to the widget's own controller.

Add the following three lines to /__init__.py just before the return config.make_wsgi_app() line:

from widgets import UserGraph
jit_view = lambda c, r : UserGraph.request(r)
config.add_route('jit_data', '/jit_data', view=jit_view, xhr=True)

And we're done. Restart the app and checkout http://localhost:6543/1 and it might look something like this.

tw2.jit.SQLARadialGraph in the default pyramid_alchemy app

You can, of course, tweak all kinds of style and functional parameters on SQLARadialGraph like those outlined near the end of my post on using SQLARadialGraph in a Turbogears 2.1 app.

Maybe you disagree, but the Pyramid implementation above went much more smoothly than the TG 2.1 setup. I think I like it.

View Comments

sqlalchemy + the JavaScript InfoVis Toolkit (jit)

Mar 06, 2011 | categories: python, toscawidgets, turbogears View Comments

I've been working on some new ToscaWidgets2 widgetry. Today's post is a tutorial on how to use tw2.jit.SQLARadialGraph with the Turbogears 2.1 framework. You can check out the entire source tree for this tutorial from my github page.

I really like tw2.jit.SQLARadialGraph and have been getting overly-excited about it: foaming at the mouth, rambling... I've tried to cut all that out of this post and just give you the details on how to get started using it and Turbogears 2.1. In short, SQLARadialGraph itself is a python web component that produces an interactive graph of your database via javascript and asynchronous requests for JSON data. Most all of its real rendering work is accomplished with the awesome JavaScript InfoVis Toolkit by Nicolas Garcia Belmonte.

For this post, first we'll configure Turbogears 2.1 to use Toscawidgets 2 middleware. Second we'll modify our new app's bootstrapping process to insert some random data into its development sqlite database. Third, we'll configure and display an instance of tw2.jit.SQLARadialGraph to visualize the data we inserted.

1. Setting up Turbogears

Start with a fresh TG 2.1 quickstarted app by running $ paster quickstart tw2.jit-tg2.1-demo. It will ask you some questions -- for this tutorial we are using mako templates and we are using authentication.

virtualenv

Jump into your newly quickstarted app's directory and run $ virtualenv --no-site-packages virtualenv and $ source virtualenv/bin/activate to cordon off your app's dependencies from your system-wide python site-packages directory.

Configure TG 2.1 for Toscawidgets 2

Add the following three lines to the install_requires argument in your setup.py file.

        "repoze.what-pylons",
        "tg.devtools",
        "tw2.jit",

A fresh Turbogears 2.1 quickstarted app depends on Toscawidgets 1 by default. We'll be using Toscawidgets 2 so we need to remove all the old references as well as tell TG2.1 to use the tw2 middleware instead of tw1.

Remove the following three lines from tw2jittg21demo/controllers/root.py:

from tgext.admin.tgadminconfig import TGAdminConfig
from tgext.admin.controller import AdminController
 ... < snip > ...
    admin = AdminController(model, DBSession, config_type=TGAdminConfig)

Remove the following one line from tw2jittg21demo/lib/base.py:

from tw.api import WidgetBunch

Add the following two lines to the bottom of tw2jittg21demo/config/app_cfg.py:

base_config.use_toscawidgets = False
base_config.use_toscawidgets2 = True

You will also need to enable the query property on all models.

Uncomment the following line in tw2jittg21demo/model/__init__.py:

DeclarativeBase.query = DBSession.query_property()

Test it all with the following commands.

$ python setup.py develop
$ paster setup-app development.ini
$ paster serve --reload development.ini

And point your browser at http://localhost:8080. If all has gone well, you should see the default index page for your newly quickstarted TG2.1 web-app.

2. Add some `interesting` data

We'll use the existing models defined in tw2jittg21demo/model/ to make this tutorial shorter and smoother.

Edit tw2jittg21demo/websetup/bootstrap.py (which is the code that gets run when you issue $ paster setup-app development.ini) and add the following two new function definitions just above the definition of the bootstrap function.

from random import choice, randint

def add_random_users():
    """ Add 9 random users """
    import string
    chars = string.letters
    for first in [u'Sally', u'John', u'Tim']:
        for last in [u'Anderson', u'Flanderson', u'Block']:
            user = model.User()
            user.user_name = unicode((first[0] + last).lower())
            user.display_name = u'%s %s' % (first, last)
            user.email_address = u'%s@socialistworker.org' % user.user_name
            user.password = u''.join([choice(chars) for i in range(12)])
            model.DBSession.add(user)

    model.DBSession.flush()

def add_random_groups():
    """ Generate a number of random groups and add users to them """
    for name in ['developer', 'system admin', 'shmeveloper', 'crispin gladbin']:
        group = model.Group()
        group.group_name = name
        group.display_name = (u"%ss group" % name).title()
        model.DBSession.add(group)

        all_users = model.User.query.all()
        for i in range(randint(0, len(all_users)-2)):
            user = choice(all_users)
            while user in group.users:
                user = choice(all_users)
            
            group.users.append(user)

    model.DBSession.flush()

These new functions still need to be called during the boostrap process, so add two invocation lines just above the transaction.commit() line at the end of the boostrap function.

        model.DBSession.add(u1)
        model.DBSession.flush()

        add_random_users()
        add_random_groups()

        transaction.commit()
    except IntegrityError:
        print 'Warning, there was a problem adding your auth data, it may have already been added:'

Blow away and re-create your database with the following commands:

$ rm devdata.db
$ paster setup-app development.ini

Run $ paster serve --reload development.ini and point your browser at http://localhost:8080 again to make sure nothing is broken.

3. Visualize the database with tw2.jit.SQLARadialGraph

Make the widget available in your root controller

Create a module tw2jittg21demo/widgets.py with the following content:

from tw2jittg21demo import model
from tw2.jit import SQLARadialGraph

def makeUserGraph():
    class UserGraph(SQLARadialGraph):
        id = 'whatever'
        base_url = '/jit_data'
        entities = [model.User, model.Group, model.Permission]
        excluded_columns = ['_password', 'password',
                            'user_id', 'group_id', 'permission_id']
        width = '920'
        height = '525'
        rootObject = model.User.query.first()
    
    return UserGraph

Modify your root controller in tw2jittg21demo/controllers/root.py to make use of the new widget.

Add the following import above the RootController definition:

from tw2jittg21demo.widgets import makeUserGraph

Modify the index(self) method so that the return statement looks like:

        return dict(page='index', widget=makeUserGraph())

And add a new method to serve json data to the jit widget.

    @expose('json')
    def jit_data(self, *args, **kw):
        """ Serve data from the tw2.jit built-in controller """
        return makeUserGraph().request(request).body

Display the widget in your root template

Replace all of the contents of tw2jittg21demo/templates/index.mak with the following two lines:

<%inherit file="local:templates.master"/>
${widget.display() | n }

Give it a spin

Point your browser once again at http://localhost:8080 and you should be greeted by something like the following:

Screenshot of the tw2.jit.SQLARadialGraph in action

Getting fancy

tw2.jit.SQLARadialGraph can make use of various method defined on the sqlalchemy entities of which its been made aware. One is the __unicode__(self) method which is already present on our models from the TG2.1 quickstart process. Another is __jit_data__(self) which must return a json-ifiable python dict.

In the future, we expect to support more attribute, but at the time of this writing the only attribute that is actually used on the client side is the value of an hover_html key if it is present at all.

Add the following two methods to your tw2jittg21demo.model.User class which is defined in tw2jittg21demo/model/auth.py:

    @property
    def gravatar_url(self):
        """ Return a link to the gravatar image for this email addy """
        import hashlib
        hsh = hashlib.md5(self.email_address).hexdigest()
        base = "http://www.gravatar.com/avatar/{hsh}?d=monsterid"
        return base.format(hsh=hsh)

    def __jit_data__(self):
        """ 'hover_html' is the only supported key at present """
        return {
            'hover_html' : """
            <h2>{display_name}</h2>
            <img src="{gravatar_url}" />
            <ul>
                <li>{user_name}</li>
                <li>{created}</li>
            </ul>
            """.format(gravatar_url=self.gravatar_url, **self.__dict__)
        }

Restart your webapp and re-visit http://localhost:8080. You should see fancy pop-ups now when you mouseover any entity for which a __jit_data__ method returns a dict containing a hover_html key.

sqlalchemy entities can provide tw2.jit.SQLARadialGraph with content to be displayed on mouseover

Style

Lastly, you may want to re-style the jit graph to fit your page. Modify tw2jittg21demo/widgets.py by adding the following import statement at the top:

from tw2.core import JSSymbol

and by adding the following extra specifications to the UserGraph class:

        # Try to match colors to the TG banner
        backgroundcolor = '#FFFFFF'
        background = { 'CanvasStyles': { 'strokeStyle' : '#FFFFFF' } }
        Node = { 'color' : '#ffcb2f' }
        Edge = { 'color' : '#307e8a', 'lineWidth':1.5, }

        # Override the label style
        onPlaceLabel = JSSymbol(src="""
            (function(domElement, node){
                domElement.style.display = "none";
                domElement.innerHTML = node.name;
                domElement.style.display = "";
                var left = parseInt(domElement.style.left);
                domElement.style.width = '120px';
                domElement.style.height = '';
                var w = domElement.offsetWidth;
                domElement.style.left = (left - w /2) + 'px';

                domElement.style.cursor = 'pointer';
                if ( node._depth <= 1 )
                    domElement.style.color = 'black';
                else
                    domElement.style.color = 'grey';
            })""")

Once again restart your webapp and reload the page to get the following:

tw2.jit.SQLARadialGraph styled to fit more nicely with the TG2.1 default appearance

Outties

I hope this post was helpful and got you interested enough to check out the code and improve on it. Comments, questions, and patches are all appreciated.

View Comments

Namespace refactor for tw2.jquery plugins

Feb 04, 2011 | categories: python, toscawidgets, oops View Comments

After consulting with Joseph Tate, we came to the decision to refactor the namespace for jquery plugins in ToscaWidgets2. Everything previously known as tw2.jquery.plugins.* is now known as tw2.jqplugins.*.

It all boils down to fighting with the tw2.jquery non-namespace. A jquery plugin package would live in ..../site-packages/tw2/jquery/plugins/someplugin and would have to ship its own file to ..../site-packages/tw2/jquery/__init__.py. However, tw2.jquery's own __init__.py file was non-empty. In order to not break everything, jquery plugin packages would have to mirror tw2.jquery-proper's own content but in the end still break the rule suggested in the second-to-last paragraph of this section of the setuptools documentation.

Apologies to anyone adversely affected who previously depended on any tw2.jquery.plugins.* packages. The following four of mine were affected, renamed, and should no longer be prone to big changes.

Lastly, if you do have projects that depend on anything in the tw2.jquery.plugins namespace, the following command should fix you up:
$ find . -name "*.py" -exec sed -i 's/jquery.plugins/jqplugins/g' {} \;

View Comments

« Previous Page -- Next Page »