[orm-devel] Access to attributes before a query

Diedrich Vorberg diedrich@tux4web.de
Sat, 16 Nov 2002 18:04:58 +0100

Hi Mike,

>However, new dbclass object instances do not have attributes matching
>the column names until after an insert / select or when explicitly
>initialized. i.e.
>    g = Groups()
>    g.name - will raise AttributeError
>if group_id:
>    g = ds.select(Groups, group_id).fetchone()
># else create an instance
>    g = Groups()
>I think (bear in mind I am still a relative Python newbie) that this
>kind of usage is more or less consistant with how someone might expect a
>persistence scheme to work.

If you run this program:

   #!/usr/bin/env python

   class thing: # a do nothing class

   aThing = thing()
   print aThing.an_atribute

you'll get the same AttributeError, so this behaviour is consitant 
with what you'd expect from python.

I can see your point however, that this seems a little absurd
considering that the class' (=the tables) attributes (columns) have
been previously defined using the columns dict.

Two questions to consider:

  o if you expect an unset attribute to contain something, what should
    it contain? None, 0 or "" or a previously defined default value?
  o another problem I have thought about: SQL allows for the 
    definition of default values. Fixed default values would be no 
    problem to implement, but what about values that call a
    SQL function like NOW() or NEXTVAL(some_sequence)? Should we make 
    a SELECT after each INSERT to retrieve this kind of data from the 
    db? We have to do a SELECT to get the NEXTVAL() for SERIAL or 
    AUTO INCREMENT columns anyway.

># populate a form with instance defaults or data if editing an existing
>form.add_widget('hidden', 'id'  , value=group_id)
>form.add_widget("string", "code", title="Code", value=g.code, size=20,
>self.add_widget("string", "name", title="Group name", value=g.name,
>size=20, required=1)
>self.add_widget("checkbox", "is_login_allowed",
>value=num_bool(g.is_login_allowed), title="Allow login?")

I've run accross the same problem. This is how my code looks:

if item.oid(): # the oid() function returns a PostgreSQL OID value or
               # simply 1 if we don't use PostgreSQL. The function 
               # should probably be renamed/aliased isStored() or so.
               # If the dbobj has not been inserted, yet, it will 
               # return None.
  title = item.title
  description = item.description
  price = "%5.2f" % item.price
  title = ""
  description = ""
  price = "0.0"

# create form...

Also, bear in mind that

   g = Groups()

results in an SQL query as

   INSERT INTO item () VALUES ()

which simply won't work. You need to populate the instance (dbobj)
with some data to get a valid query. The reason I did it this way is,
we can't just insert NULL for an unset column, because there is a
difference in inserting NULL and insering nothing. Take a relation
like this for instance (this is PostgreSQL btw):

     id SERIAL,
     test VARCHAR(20),

and then do

   INSERT INTO test (test, created) VALUES (NULL, NULL); 
   INSERT INTO test (test) VALUES (NULL);

you'll get

   test=# select * from test;
    id | test |            created            
     3 |      | 
     4 |      | 2002-11-16 18:00:08.602113+01
   (2 rows)

the first created an all-empty column, the latter did what we wanted. 

Any comment or suggestions on how to deal with this kind of problem 
is very welcome!


           _..._                            Diedrich Vorberg
         .'     '.
        /  _   _  \                         http://www.tux4web.de
        | (o)_(o) |                         info@tux4web.de
         \(     ) /            .---.
         //'._.'\ \           /     \       Internet Dienstleistungen
        //   .   \ \          \.@-@./       und 'Consulting'.
       ||   .     \ \         /`\_/`\
       |\   :     / |        //  _  \\      Linux Rules!
       \ `) '   (`  /_      | \     )|_
     _)``".____,.'"` (_    /`\_`>  <_/ \
     )     )'--'(     (    \__/'---'\__/
      '---`      `---`