Slashdot Mirror


TurboGears: Python on Rails?

gcantallopsr writes "If you liked Ruby on Rails and its 15m intro video (.mov) you will probably like TurboGears and its 20 minute wiki tutorial. (.mov) It shows you the development of a simple wiki in just 20 minutes, and there is a text version of the tutorial. TurboGears uses Python, SQLObject, CherryPy, Kid, MochiKit and some extra pythonic glue to help you to (in their own words) 'Create a database-driven, ready-to-extend application in minutes. All with designer friendly templates, easy AJAX on the browser side and on the server side, not a single SQL query in sight with code that is as natural as writing a function.'"

22 of 279 comments (clear)

  1. My Experience by HogynCymraeg · · Score: 3, Informative

    I've used Python/SQLObject/CherryPy on a project before. It's very quick to code something useful. SQLObject will change the way you think about how you integrate DBs to web applications. All in all, it's well worth checking out.

  2. Re:no sql? by quigonn · · Score: 5, Informative

    It shows a high level of abstraction when you access the DB by simply loading/persisting objects instead of having to handle queries, result sets, records and all the other low-level stuff. And abstraction (in this case) is good, as it helps the developer concentrate on the relevant parts of the program.

    --
    A monkey is doing the real work for me.
  3. SQLObject rocks! by SimHacker · · Score: 5, Informative

    One of the nicest features of SQLObject is that it insulates you from the peculiararities of the database's SQL syntax, so you don't need to put any SQL code directly into the Python code (but you can if you need to for efficiency or if you're willing to write non-portable code).

    The SQL database abstraction layer is an important feature of SQLObject, that Ruby on Rails doesn't currently support -- you have to write database dependent SQL code mixed in with your Ruby code.

    SQLObject lets you write generic SQL queries with normal Pythonic expressions and operators, which are automatically translated into the database dependent SQL syntax by the database driver. So you don't have to change any of your Python code to port it to a different database, and you don't have to mix together two different notations, or quote a bunch of SQL strings in your Python code. It's a much more "pythonic" way of database programming than raw SQL.

    The great thing is that it's so convenient and the syntax is so simple, that you can use the interactive Python shell to browse and test out and edit your database. It's trivial enough to type in some Python code on the keyboard that loops over the results of a query, performs some complex logic, and validates and edits a bunch of rows in the database. Much more powerful and easier to use than anything you can do with raw SQL.

    -Don

    --
    Take a look and feel free: http://www.PieMenu.com
    1. Re:SQLObject rocks! by Osty · · Score: 3, Informative

      The SQL database abstraction layer is an important feature of SQLObject, that Ruby on Rails doesn't currently support -- you have to write database dependent SQL code mixed in with your Ruby code.

      There's your problem -- you're mixing SQL code in with your app code. Bad developer! Bad! You're introducing SQL injection holes (I don't care how well you think you're filtering your input, chances are you missed something, especially if you're trying to do so in a DBMS-agnostic way). While an abstraction layer like SQLObject may be better in that regard because it's main focus is interfacing with SQL and thus should be more focused on catching these kinds of bugs, if it's mixing in dynamic SQL queries there's a good chance it also has SQL injection holes.

      There's a reason why stored procedures are important, and it doesn't have anything to do with perceived performance increases from not having to re-parse the same SQL code every call (that's definitely a benefit, but it's minor). In this case, stored procedures shelter you from SQL injection attacks (assuming, of course, that your stored procedures aren't just dumb "take a string and 'exec' it as SQL code" queries). You may not agree with the people that tell you to use stored procedures to keep your business logic near the data, or that using stored procedures allows you to easily expose only the permissions required (GRANT EXECUTE on the stored proc, rather than having to figure out what tables need INSERT permissions, which ones need SELECT permissions, etc for each app that uses this database), but I don't see how you could argue their protection against injection. Yes, parameterized queries allow you to write dynamic SQL code with some level of injection protection, but that still leaves you with the downside of having SQL mixed into your code.

      It's trivial enough to type in some Python code on the keyboard that loops over the results of a query, performs some complex logic, and validates and edits a bunch of rows in the database. Much more powerful and easier to use than anything you can do with raw SQL.

      I call BS. First off, SQL is a set-based language. Very rarely do you need to loop over a result set (if you find yourself looping in SQL code, you're not thinking hard enough). Whatever "loop and operate" action you'd take with Python can be done quicker and more efficiently with SQL code than with app code. Second, for Python code to loop over a result set means it has to get that result set. If your database is not local to your web server (bad idea!), that means network I/O costs. You can and should avoid that cost by processing the data first at the SQL Server (hey, stored procedures again! Why return 100,000 rows that you're going to process down to 1,000 when you could just return the 1,000 processed rows in the first place? Why return anything at all when you're going to insert/update data based on what's in a different table?). Finally, while it may be "easier" for a developer proficient in Python and not the SQL dialect used by your chosen DBMS, that's a cop-out. As so many people are so fond of saying, you should use the right tool for the job. In this case, you're trying to use the hammer of Python to pound a screw, when you'd be better off with the screwdriver of SQL. Sure, you may be able to pound that screw into the wood, but it'd be quicker and easier to do it in SQL. Maybe you don't want to learn SQL, in which case you probably shouldn't be working with a database. You have a responsibility to learn how to use the tools you're going to apply to a problem.

      I've intentionally ignored the problem of database portability, because a) you should be using stored procedures, which means you'll want to port them yourself anyway for maximum benefit, b) you should be using a proper DBI layer such that you just have to tell it, "I'm using Oracle now instead of Postgres, do the right thing", and c) because you're using stored procedures, you won't be switching to a DBMS that doesn't support the (*cough*MySQL*cough*) (and yes, I know MySQL "will" support them, but that's still some way off in non-beta form).

    2. Re:SQLObject rocks! by Trejkaz · · Score: 4, Informative

      There's a reason why stored procedures are important, and it doesn't have anything to do with perceived performance increases from not having to re-parse the same SQL code every call (that's definitely a benefit, but it's minor). In this case, stored procedures shelter you from SQL injection attacks

      Whereas this is true, it's also true that using "?" parameters for any user-entered values can solve the SQL injection problem just as well.

      --
      Karma: It's all a bunch of tree-huggin' hippy crap!
    3. Re:SQLObject rocks! by fireboy1919 · · Score: 2, Informative

      In this case, stored procedures shelter you from SQL injection attacks

      I'm not sure that they do. In fact, I'd go so far as to say that this doesn't make much sense at all. Not that its hard to protect against injection attacks, though.

      Let's say you have a stored procedure called "getnumber" that takes two args.
      Your goal is that this procedure is going to protect you from injection attacks; that you can put two untrusted args into it and you won't have to worry about someone using the procedure to do something you don't want them to do.

        So you run
      "select * getnumber(arg1,arg2);"

      Is this vulnerable to injection attacks? Yes.

      If arg2="32); create user..."

      You see the problem? Stored procedures didn't help. Actually, I'd like to know what stored procedures will do for you that does help.

      On the other hand, having a single place that validates the input does help - pretty much every time, and you're invulnerable. Its not nearly as hard as making sure that there's no buffer overflows.

      This is all that is necessary and sufficient to protect against SQL injection:
      1) Any quote symbols in the user input are escaped so that they won't be considered quotes.
      2) Each user-supplied value is quoted before being put into an SQL statment.
      3) Users are allowed to enter values only. If users are allowed to enter column names, then the data must be validated against all allowed column names. But generally this is stupid. Best to let users enter data only, never metadata.
      4) Users may not enter any SQL.

      Pretty much all of these database converters have one or two points of entry that do 1-2 before doing any kind of optimization/fetching/whatever, and they don't really allow you to do 3-4. Of course, maybe I'm wrong and the GP knows about some mystical forms of SQL injection attacks that I don't. If so, I would certainly like to hear about any injection attempts that can fool this sort of thing. I would also like to hear about some big ORM (object-relational mapping) tools that prove that what the GP says isn't FUD.

      Keep in mind that escaped values are escaped both when they're entered, and when they come out of a database. You pretty much always have to manually unescape them if you want to show them the original way.

      --
      Mod me down and I will become more powerful than you can possibly imagine!
  4. Re:Video software by jrockway · · Score: 3, Informative

    Since it was made on a mac, my guess is Snapz Pro X.

    http://www.ambrosiasw.com/utilities/snapzprox/

    --
    My other car is first.
  5. torrent (just in case) by Anonymous Coward · · Score: 2, Informative
  6. Re:Video software by mykdavies · · Score: 4, Informative

    What software do people use for making these neat videos?

    vnc2swf

    And to bring us (nearly) back on topic, the latest version is written in python!

    --
    The world has changed and we all have become metal men.
  7. Re:no sql? by wootest · · Score: 5, Informative

    Other people have answered in-depth, but the short answer is:

    a) You do not need to worry about which vendor's dialect of SQL syntax you're using - provided you know how to create and populate the tables in any database system, you can switch at the drop of a hat if you need or want to.

    b) Provided the layers are stable, it protects you from SQL query injections. The abstraction layer does the escaping for you.

    c) Abstracted queries makes queries 'just another function/method call', and you get ordinary data structures back. This in combination with a) and b) and a competent framework (Rails, Django, TurboGears, Cake, Trax, WebObjects) makes coding much quicker as you don't have to keep the semantics of SQL and your database in mind - just the model itself.

    There are *many* nuances to this, but the above three are some of the most pertinent ones. Peruse the other comments if you want to get in-depth.

  8. Tried it, too bitty by Boffy · · Score: 3, Informative

    Tried TurboGears, but the fact that it's a glue was way too appparent. I then moved on to trying Django and fell in love. All the stuff TurboGears can do Django can too, but natively.

    1. Re:Tried it, too bitty by aleph · · Score: 3, Informative

      Still downloading the movie from TurboGears (tried streaming, but well.. That wasn't happening too well :)), but I have been playing with Django a bit the past few days.

      It does look kind of cool, the admin interface is good for _simple_ objects, but seems to start to fall down when you want to construct interesting relationships between the objects, and I haven't started to look into doing custom (or using generic) create/update templates yet.

      That being said I'm still suffering a bit of paradigm lag since i've mostly been dealing with Zope/Plone for the past couple of years, and while that platform isn't without it's problems, it does have a lot of nice features you begin to take for granted.

      I also came across areas where Django would silently fail to do things in the admin interface with no sign of an error anywhere (it wasn't even attempting to insert the new object in the db, nor raising an exception anywhere). That kind of behaviour makes me a bit nervous :p

  9. Re:no sql? by mixmasterjake · · Score: 4, Informative

    Persistance layers are cool for a lot of reasons. Though, it definitely takes some getting used to for those of us who have developed a lot of SQL driven applications.

    Don't let anyone fool you into thinking that a persistance layer will be less development work for you - I have found this to be untrue. I can use automated tools to get myself 80% of the way there. For anything substantial, though, it always seem to wind up being more work as I figure out how to configure & trick the persistance layer into giving me my data in the most efficient way. This can be frustrating when you know how to accomplish the same thing in 5 seconds using plain SQL. Maybe it's just me?

    But, if you do manage to get over the hump, the benefit is that your business logic layer is very clean with no DB code whatsoever. If you use it properly, you can get 100% separation between these layers.

    If you're using a strongly typed language, you get the added bonus of compile-time checks for certain illegal assigment errors. You don't have to fumble around with things like converting dates into SQL. You don't have to check for SQL injection. Lots of other little things.

    --
    TODO: come up with a clever sig
  10. Twisted by jcr · · Score: 4, Informative

    Also worth checking out: Twisted. I haven't had occasion to use it myself, but people I know swear by it.

    -jcr

    --
    The only title of honor that a tyrant can grant is "Enemy of the State."
  11. Re:Rails everywhere. by arevos · · Score: 4, Informative
    To me it seems like a silly exercise to replicate rails in python or what have you. Ruby is easy to pick up and a nice language to boot. Why bother really? Just learn ruby and get on board.

    Whilst Rails is an excellent framework for web applications, I've found that it gets exponentially more difficult to work with when your database structures grow more complex than interconnected lists. I recently designed a double-booked accounts program in Rails, and whilst most of the code was simple to design, I quickly got bogged down in handling the accounts-tree and the double-booking of financial records. Here the documentation ran out, and I was forced to go through the Rails source to discover a solution to my problem, which turned out to be less than optimum.

    Secondly, whilst I have done a fair bit of work in Ruby, I can't help but prefer Python. If there's little difference between Rails and, say, Turbogears, Django or Subway, then surely it comes down to personal preference. Python web frameworks appear to take a more piecemeal approach than Rail, which can provide a more flexible solution in certain situations.

    Can't say I much like SQLObject's syntax, though; but CherryPy seems rather elegant.

  12. Re:Rails everywhere. by Anonymous Coward · · Score: 1, Informative

    Have you even looked at Ruby? It is not a functional language by any stretch -- it is very similar to Python and Perl. It is by far the cleanest one of the three built with objects from the ground up.

  13. Re:no sql? by jrcamp · · Score: 2, Informative
    For anything substantial, though, it always seem to wind up being more work as I figure out how to configure & trick the persistance layer into giving me my data in the most efficient way. This can be frustrating when you know how to accomplish the same thing in 5 seconds using plain SQL. Maybe it's just me?

    If there is something you need to specifically query by hand in SQL you just use find_by_sql in Rails. I'm not sure how this is configuring and tricking it?

  14. Re:Perl on rails? by holy+zarquon's+singi · · Score: 4, Informative
    --
    "...we should just trust our president in every decision that he makes and we should just support that." B.Spears 2003
  15. Re:Rails everywhere. by Ian+Bicking · · Score: 5, Informative
    To me it seems like a silly exercise to replicate rails in python or what have you.
    1. TurboGears is not a Rails clone.
    2. Most parts of TurboGears existed before Rails: CherryPy, SQLObject, FormEncode (and Python of course).
    3. Kid is most closely related to Zope Page Templates (from the Python world), not anything from Rails.
    4. MochiKit has a certain relationship to Prototype (the Javascript library from Rails), and is compatible with it. However, it's not that the author particularly likes Prototype.

    Rails has taught us some important lessons, but they aren't really technical lessons:

    1. We shouldn't sit around and say "oh, those poor people using PHP/Java/etc, too bad they don't know about what you can do using X". Instead we should talk more loudly and insistently about the advantages of our platforms. If you do it right people will pay attention.
    2. We haven't concentrated enough on full-stack integration. We've been overvaluing decoupled pick-and-choose components. Full-stack integration doesn't have to mean coupling -- it can just be a matter of presentation, and making sure tools are complimentary. Not all of the Python frameworks are coming at it from this direction, but TurboGears very much is.
    3. Things like screencasts are nice.

    After looking at various pieces of Rails, these lessons have stood out to me, but the particular technology in Rails has not. Sure, there are some good ideas, but nothing radical, and there's good ideas everywhere waiting to be mined. We're not beneath mining other people's ideas, but it does not follow that the result is merely a "replication" in part or in whole.

    As for Ruby: I think the two languages are largely equivalent in terms of what you can do. I would not say the same about PHP or Java. As for Rails specifically, I think it is only ahead of Python options in the second derivative. With conscious players the second derivative doesn't mean a whole lot.

  16. Re:no sql? by Ian+Bicking · · Score: 2, Informative

    Well, no points for the docs on this one (hey, it's open source) but there is some help for outer joins noted here.

  17. Re:There are too many ways to answer that by pthisis · · Score: 2, Informative

    Python has ONE (ok, one and a half if you count Jython) implementation

    I'm not disputing your basic point, but there are many Python implementations. Off the top of my head:

    CPython (aka "standard" Python)
    Jython
    Stackless Python
    IronPython
    PyPy

    CPython, Stackless, and Jython are real production implementations.

    PyPy is rapidly headed that way (and already self-hosting and passes more than 95% of the Python compliance tests). One of the primary developers is Armin Rigo, who did psyco (the specializing dynamic Python compiler that achieved speedups of up to a factor of 100 for numeric code).

    IronPython looks to be abandoned.

    --
    rage, rage against the dying of the light
  18. You're making the wrong comparison by Estanislao+Mart�nez · · Score: 2, Informative

    You're saying that a statement that does *less* than the other one is easier to understand.  Way to go, Sherlock.

    Now let's try a comparison between statements that do the *same* thing.  First, the one using the block to manage resource allocation and deallocation:

        Net::HTTP.start( 'www.ruby-lang.org', 80 ) do |http|
          print( http.get( '/en/LICENSE.txt' ).body )
        end

    ...and second, the *real* equivalent without blocks:

        begin
          http = Net::HTTP.start( 'www.ruby-lang.org', 80 )
          print( http.get( '/en/LICENSE.txt' ).body )
        ensure
          http.close
        end

    Needless to say, the block version is shorter.

    Anyway, this pattern you see here is one of the most common Ruby idioms, which you should get the hang of if you're learning the language: using blocks to decouple code that manages a resource *through its whole lifecycle* from code that use the resource.  It's always like this:

        Resource.acquire {|resource|
          # do stuff that requires resource
        }
        # resource has been released, without you having to say so,
        # even if the there was an exception

    The same pattern applies to files, network connections, database result sets, thread locks, anything.  Sure, it's unfamiliar to *you*, but you only need to learn the pattern *once*, and you reuse it all the time for different kinds of resources.

    And to top it off, you can write your own methods like acquire() above in Ruby itself, just by using yield.  This is not some special syntax sugar for resource management--this is just blocks.  Here's the pattern for writing a method like acquire():

        def acquire
          begin
            resource = low_level_acquire()
            yield resource
          ensure
            resource.low_level_release()
          end
        end