DiMarzio
DiMarzio

Reputation: 153

web2py: DAL find() not working

tl;dr: read the last paragraph

I have a function which is supposed to return three row objects in a list. And the row objects are as following:

The minings have no direct relationship with savestates, so I have to trace the correct savestate through table called turn. The relationships are as follows: savestate 1:n turn 1:1 mining.

This is what I have so far:

def get_latest_minings(save_id):
    return_list = []
    #get all turn.ids that belong to this savestate:
    savestate_turns = [s.id for s in db(db.turn.savestate_id == save_id).select(db.turn.id)]
    #get all minings that belong to these turns:
    save_minings = db(db.mining.turn_id.belongs(savestate_turns)).select()
    #loop to get three objects:
    for i in range(1,4):
        #from save_minings, get all minings, whose process is i:
        line_minings = save_minings.find(lambda row: row.process == i)
        #initialize loop variables:
        latest_date = 0
        latest = None
        #loop to find the biggest finish_date:
        for m in line_minings:
            if m.finish_date > latest_date:
                latest_date = m.finish_date
                latest = m
        #add the row with the biggest finish_date to the list:
        return_list.append(latest)
    #return locals() for testing purposes:
    return locals()
    #actual return:
    #return return_list

This however doesn't work as intended. This is what it returns:

https://www.dropbox.com/s/ns6mq9414vw25s9/get_latest_minings.png?dl=0

I have run some separate tests and I have found the problem to be with the line: line_minings = save_minings.find(lambda row: row.process == i). Every other line works as it should. What is wrong here? Another question: can this be optimized more? I'm particularly curious about tracing the correct savestate.

Upvotes: 0

Views: 93

Answers (1)

Remco
Remco

Reputation: 435

  1. On your first question What is wrong here?:
    Is it possible that the field type of the process is set to string or text or anything other than integer?

  2. Your second question can this be optimized more?: yes. probably.

Without the rest of your code at hand, here's a shot:

def get_latest_minings(save_id):
    # from the minings that belong to this savestate:
    query = (db.mining.turn_id == db.turn.id) & (db.turn.savestate_id == save_id)

    # [optional] if you want to restrict the process ids only to be 1,2 or 3. 
    # given your output, you only have 1 and 2 so it would be useless 
    # again, mind the datatype, don't compare strings to integers. 
    # but for completion, i'll stick to your original functionality
    query &= (db.mining.process.belongs([1,2,3]))

    # get the latest finish date per mining process
    maxdate = db.mining.finish_date.max()
    save_minings = db(query).select(maxdate, db.mining.process, groupby=db.mining.process)

    # create a lookup structure with processid as key
    last_date_lookup = {row.mining.process:row[maxdate] for row in save_minings}
    # query the lookup structure per process id or None if not available
    return [last_date_lookup.get(pid) for pid in range(1,4)]

It's untested of course, and not even parsed or anything but I hope it helps.

Also remember there might be an error about web2py's DAL not being able to find a certain field. I've noticed the returned rows need to be queried differently when joined tables are queried. Mostly you can see this in row.mining.process where the table name is used instead of row.process which is perfectly use-able when querying only the mining table.

Upvotes: 1

Related Questions