How to create a controller method in Turbogears that can be called from within the controller, or rendered with a template

Question!

If you have a controller method like so:

@expose("json")
def artists(self, action="view",artist_id=None):
    artists=session.query(model.Artist).all()
    return dict(artists=artists)

How can you call that method from within your controller class, and get the python dict back - rather than the json-encoded string of the dict (which requires you to decode it from json back into a python dict). Is it really necessary to write one function to get the data out of your model, and another to pack that data for use by the templates (KID, JSON)? Why is it that when you call this method from in the same class, e.g.:

artists = self.artists()

You get a json string, when that's only appropriate if the method is called as part of a HTML request. What have I missed?



Answers

I normally approach this by having a 'worker' method, which queries the database, transforms results, etc., and a separate exposing method, with all the required decorators. E.g.:

# The _artists method can be used from any other method
def _artists(self, action, artist_id):
    artists = session.query(model.Artist).all()
    return dict(artists=artists)

@expose("json")
#@identity.require(identity.non_anonymous())
# error handlers, etc.
def artists(self, action="view", artist_id=None):
    return self._artists(action=action, artist_id=artist_id)


Nested classes (probably best to avoid the word "inner" as nested classes in C# are somewhat different to inner classes in Java) can indeed be very useful.

One pattern which hasn't been mentioned is the "better enum" pattern - which can be even more flexible than the one in Java:

public abstract class MyCleverEnum
{
    public static readonly MyCleverEnum First = new FirstCleverEnum();
    public static readonly MyCleverEnum Second = new SecondCleverEnum();

    // Can only be called by this type *and nested types*
    private MyCleverEnum()
    {
    }

    public abstract void SomeMethod();
    public abstract void AnotherMethod();

    private class FirstCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // First-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // First-specific behaviour here
        }
    }

    private class SecondCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // Second-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // Second-specific behaviour here
        }
    }
}

We could do with some language support to do some of this automatically - and there are lots of options I haven't shown here, like not actually using a nested class for all of the values, or using the same nested class for multiple values, but giving them different constructor parameters. But basically, the fact that the nested class can call the private constructor gives a lot of power.

By : Jon Skeet


You should limit the responsibilities of each class so that each one stays simple, testable and reusable. Private inner classes go against that. They contribute to the complexity of the outer class, they are not testable and they are not reusable.



This video can help you solving your question :)
By: admin