_after_delete callback - how to access info of deleted Set?

301 views
Skip to first unread message

Jurgis Pralgauskis

unread,
May 8, 2013, 6:10:05 PM5/8/13
to web...@googlegroups.com
Hi, 

I look at example:

how can I find out what is the value of person.id from the set without select?
(<Set (person.id = 1)>,)

as I tried:
s.select(..)[0]   # it worked for update
but got 

Traceback (most recent call last):
File "/home/nijole/Downloads/EasyVet/web2py/gluon/restricted.py", line 212, in restricted
exec ccode in environment
File "/home/nijole/Downloads/EasyVet/web2py/applications/apskaitele/controllers/appadmin.py", line 569, in <module>
File "/home/nijole/Downloads/EasyVet/web2py/gluon/globals.py", line 194, in <lambda>
self._caller = lambda f: f()
File "/home/nijole/Downloads/EasyVet/web2py/applications/apskaitele/controllers/appadmin.py", line 304, in update
if form.accepts(request.vars, session):
File "/home/nijole/Downloads/EasyVet/web2py/gluon/sqlhtml.py", line 1398, in accepts
self.table._db(qry).delete()
File "/home/nijole/Downloads/EasyVet/web2py/gluon/dal.py", line 9821, in delete
ret and [f(self) for f in table._after_delete]
File "/home/nijole/Downloads/EasyVet/web2py/applications/apskaitele/models/db.py", line 329, in <lambda>
db.Pardavimai._after_delete.append( lambda s: update_SandelioProduktai_likutis_from_Pardavimai(s.select(db.Pardavimai.sandelio_produktas)[0]) )
File "/home/nijole/Downloads/EasyVet/web2py/gluon/dal.py", line 10075, in __getitem__
row = self.records[i]
IndexError: list index out of range


Anthony

unread,
May 8, 2013, 7:06:57 PM5/8/13
to web...@googlegroups.com
If the query only has that one condition, then you can do:

s.query.second

A Set object has a "query" attribute, which is a Query object, and a Query object has "op", "first", and "second" attributes. So, s.query gets the Query object of the Set, and s.query.second gets the second operand of the "==" operator. If instead you have multiple conditions in the query, keep in mind that the operands of the "&" operator are themselves Query objects. So, if you have:

set = db((db.person.id > 10) & (db.person.name.startswith('A')))

you can extract the 10 from the first part of the query via:

set.query.first.second

In that case, set.query.first itself returns a Query (i.e., db.person.id > 10), so set.query.first.second gives you the 10.

Keep in mind that these properties of Set and Query are internal and not part of the API, so this isn't guaranteed to remain backward compatible.

Another option is to pass the Set to the str() function, which generates a string that contains the SQL produced by the query. You could then do some parsing of that string to get what you want. For example, in this case you get:

>>> str(db(db.person.id == 1))
'<Set (person.id = 1)>'

You can use a regex to get the 1 from that string.

Anthony

Jurgis Pralgauskis

unread,
May 8, 2013, 7:40:49 PM5/8/13
to web...@googlegroups.com
Thanks, 

hm, ok, my usecase is more problematic, 


db.define_table('Product',
    Field('name',),
    Field('price', 'decimal(10,2)'),
    Field('quantity', 'integer'),
    Field('quantity_sold', 'integer'), # this could be virtual - but then it does not play with queries...
)

I want to refresh quantity_sold after each Purchase (insert/update/delete)
but after delete I'd like to still access which product it has been?
if I do it before delete, the purchace is still there - and my aggregate function sums it (though I need it gone) ...

db.define_table('Purchase',
    Field('product', db.Product),
    Field('quantity', 'integer'),
)

def update_Product_quantity_from_Purchase( purchase ):
    q_sum = db.Purchase.quantity.sum()
    quantity_sold = db(db.Purchase.product== purchase.product ).select(q_sum).first()[q_sum] or 0
   db.Product[purchase.product].update_record( quantity_sold=quantity_sold )
    

db.Pardavimai._after_insert.append( lambda f,id: update_Product_quantity_from_Purchase(f) )
db.Pardavimai._after_update.append( lambda s,f: update_Product_quantity_from_Purchase(s.select()[0]) )
db.Pardavimai._after_delete.append( lambda s: update_Product_quantity_from_Purchase(s.select()[0]) ) #ERR

***
Ha, while writing I came up with workaround -  _before_delete
I add extra parameter to my update_Product... function, which tells that purchase stuff should be subtracted in advance (as it will be detelted)

def update_Product_quantity_from_Purchase( purchase, deleting=False ):
   ...
   if deleting: 
        quantity_sold -= purchace.quantity
   db.Product[purchase.product].update_record( quantity_sold=quantity_sold  )

db.Pardavimai._before_delete.append( lambda s: update_Product_quantity_from_Purchase(s.select()[0], True) ) #OK

***
ps.: Maybe similar functionality could be extended for "compute'd" field?
If it knew what foreign tables&fields it depends on, the triggers/callbacks could be added automatically?




--
 
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/M4_5THMHzH0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Jurgis Pralgauskis
tel: 8-616 77613;
Don't worry, be happy and make things better ;)
http://galvosukykla.lt

Niphlod

unread,
May 9, 2013, 4:37:55 AM5/9/13
to web...@googlegroups.com
uhm. please take into consideration that you can't hook to the "after_delete" callback if you still want to access the record that has been deleted...... use before_delete for that case.
Reply all
Reply to author
Forward
0 new messages