On Mon, Jul 05, 2010 at 11:20:31AM +0200, Till Maas wrote:
> Oleg Broytman wrote:
> >    MultipleJoin works together with a corresponding ForeignKey. .select()
> > doesn't take them into account. So either you iterate over Packages row by
> > row and use .builds attribute of every row, or construct the query
> > manually
> 
> Can you maybe give me a hint how to create the query

   I will. See below.

> Or is there some support for using custom 
> queries in SQLObject that make SQL-Injections impossible e.g. by using 
> prepared statements?

   Unfortunately, no.

> >> class PackageUpdate(SQLObject):
> >>     title            = UnicodeCol(notNone=True, alternateID=True)
> >>     builds           = RelatedJoin("PackageBuild")#
> >> 
> >> class PackageBuild(SQLObject):
> >>     nvr             = UnicodeCol(notNone=True, alternateID=True)
> >>     package         = ForeignKey('Package')
> >>     updates         = RelatedJoin("PackageUpdate")
> >> 
> >> class Package(SQLObject):
> >>     name            = UnicodeCol(alternateID=True, notNone=True)
> >>     builds          = MultipleJoin('PackageBuild',
> >>     joinColumn='package_id')
> >> 
> This is the query that does not work unexpectedly, because 
> query.append(PackageUpdate.q.builds == builds)
> updates = PackageUpdate.select(AND(*query), orderBy=order).reversed()[:20]
> creates this error:
> AttributeError: PackageUpdate instance has no attribute 'builds'

   I will explain how RelatedJoin works and the reason for the error. To
simplify my explanations I will omit class Package.

   RelatedJoins are always come in pairs - two tables points to each other.
They look rather simple, but SQLObject does some magic to implement them.
It creates an intermediate table that stores many-to-many references. There
is nothing too magical about the table - it is just an ordinary SQL table.
The only magical thing is that SQLObject creates it itself behind the scene
and builds queries when one asks for attributes build.updates and
update.builds.
   SQLObject doesn't promote these attributes to the .q. namespace, hence
you cannot use them in .select(). Really, there is no PackageUpdate.q.builds,
only update.builds (where 'update' is a row from the PackageUpdate table).

   Now we have to look under the hood. The intermediate table can be
declared in SQLObject terms. For example, to add additional columns. See
http://sqlobject.org/FAQ.html#how-can-i-define-my-own-intermediate-table-in-my-many-to-many-relationship
   In your particular case you need the table to explicitly build a join
(to overcome the limitations in SQLObject that cannot build implicit
may-to-many joins itself). The table declaration is

class PackageBuildPackageUpdate(SQLObject):
     package_build  = ForeignKey("PackageBuild")
     package_update = ForeignKey("PackageUpdate")

   (To name the intermediate table SQLObject combines the names of the
related tables in alphabetical order. You can change the name if you use
parameters intermediateTable='...')
   When one asks for update.builds SQLObject generates a query like this:

PackageBuild.select(
    PackageBuild.q.id==PackageBuildPackageUpdate.q.package_buildID &
    PackageBuildPackageUpdate.q.package_updateID==update.id)

   All you need now is to extend that very query. SQLObject can slightly
relive the pain of constructing such queries. It has a magic .j namespace
to help to build complex joins. The query above can be rewritten as

PackageBuild.select(PackageBuild.j.updates & PackageUpdate.q.id==update.id)

   Try to add your own joins to the query.

Oleg.
-- 
     Oleg Broytman            http://phd.pp.ru/            p...@phd.pp.ru
           Programmers don't die, they just GOSUB without RETURN.

------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
sqlobject-discuss mailing list
sqlobject-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss

Reply via email to