Showing posts with label relationship. Show all posts
Showing posts with label relationship. Show all posts

Thursday, May 5, 2011

TG2.1 Trouble with One to Many Relationship

Finally, I figured out what causes the 'ModelController' error in the TG2.1 Admin System Page. Thanks to Eclipse (Aptana Studio 3) and PyDev, I was able to debug and spot the cause of the trouble.
I was kind of surprised that Sprox, the module that is responsible for form-model binding, could not handle unique constraint in one to many relationship.
Due to this, all other kind of constraints on relationship will probably fail too. Perhaps UniqueConstraint also get effected.
So, mainly all other constraints that are not applied directly to the fields of the sqlalchemy models could not be handled properly by TG2.1 (sprox).

Since, unique constraint is very common in DB design, I really hope that this functionality could be handled not just in simple field but also in relationship and multi-columns unique contraint.

As for the 'elegant' solution, I have not yet find a way to do it. Perhaps, I could add validator in the relationship field/attribute (in sqlalchemy declarative model class), but no clue on how to implement it. Another thing is that even if I could do that, I am not sure it would work, since I am not even sure if relationship field would be registered to be checked by the framework.

It would be a good thing if in sprox the relationship field and the foreignkey field both are being checked as one.

As for now, I just need to do a work around to prevent adding duplicate one to many relationship.

Pretty impressed with TG2.1. This is by far the most flexible web framework that I have worked with. My suggestion to those who would use this framework is, be prepared to swim and dive in the source codes, as you definitely need to extend functionalities by overriding methods and sub-classing.

Tuesday, February 15, 2011

TurboGears 2 presenting relationship

Time for me to move on and learn TurboGears2.1. Coming from django background, I expected somewhat similar elegance in TurboGears. Something like urlpatterns, which is quite nice. I did not found something like that. A bit disappointment, because urlpatterns really such a wonderful way to map between url requests and the handlers.
The main and biggest issue with django is it's orm. I really wish somehow we can replace it with sqlalchemy and still having all the auto generated Admin Interface.
Sqlalchemy is totally awesome. If you have not used it yet, please spend sometimes with it.

Since, TurboGears supports sqlalchemy, I decided to take a look and play around with it. The awesome thing about TurboGears 2.1 it also have Administration System, which will auto generate the web interface, using python-rum and sprox.

The first time I used the Admin System, I got the UI (tables and forms) for all the tables prepared. The only issue at that time was the relationship displayed is still using 'id'. Quite confusing for the end-user.

Digging more and more about TurboGears 2.1, I learned that all of the transformations from the table schema into web UI are done via sprox, which uses '_name', 'name', (and some other values) as default values for column name matching relationship representation.

Did some more digging and I figured out how to define the desired column for relationship representation.

class: TableFiller
modifier: __possible_field_names__ = [ 'brand', 'first_name' ]
class: AddRecordForm
modifier: __dropdown_field_names__ = [ 'title' ]
class: EditableForm
modifier: __dropdown_field_names__ = [ 'name', 'info' ]

Those classes could be imported using the following:
from sprox.fillerbase import TableFiller
from sprox.formbase import AddRecordForm, EditableForm

TableFiller is for viewing, AddRecordForm is for adding new record, EditableForm is of course for edit existing record.

So, what you can do is subclass those classes, according to your need, and set either __possible_field_names__, __dropdown_field_names__ or both, to the appropriate columns. Then store the subclasses in the controller (project/app/controllers/root.py, for example).