Create a copy record button in SQLFORM?

395 views
Skip to first unread message

LoveWeb2py

unread,
May 2, 2014, 8:29:26 AM5/2/14
to web...@googlegroups.com
Hello,

There are many times when I just want to copy the values of one record in my sqlform and create a new record, but modify the content and save it. Is there an easy way to do this with web2py or would I have to write the code?

Many thanks

Oli

unread,
May 2, 2014, 9:07:43 AM5/2/14
to web...@googlegroups.com
I hope this help.

def copy_and_edit():
    """
    copy_and_edit
    """
    record = db.t_disciplin(request.args[0])

    vals = {}
    for k,v in record.items():
        if k in db.t_disciplin.fields:
            if k == 'f_title':
                v = v + "_copy"
                recname = str(v) # Needed to redirect the page to the right record
            if k != 'id':
                vals[k] = v

    db.t_disziplin.insert(**vals)

    rec = db(db.t_disziplin.f_title == recname).select().first()
    rec_id = rec.id

    # redirect for edit the new record
    redirect(URL(r=request, f='konstanten/t_disciplin/edit/t_disciplin',args=str(rec_id)))

Richard Vézina

unread,
May 2, 2014, 9:30:21 AM5/2/14
to web2py-users
keepvalues

or

row = db(...).select(db.table.record).first()

db.other_table.field1.default = row.field

form = SQLFORM(db.table, ...)

Richard


--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

LoveWeb2py

unread,
May 2, 2014, 9:33:10 AM5/2/14
to web...@googlegroups.com
Richard,

How do I assign this to a button though?

Richard Vézina

unread,
May 2, 2014, 9:39:46 AM5/2/14
to web2py-users
What do you mean?

You can redirect (A('Link', _href=URL(controler, function, vars=dict(pass_your_record_vars_here=record_vars1, ...))) to a function that do what I wrote above... Just pass record value throught vars then request.vars.field1 request.vars.field2 and assign .default= request.vars.field1

Richard

LoveWeb2py

unread,
May 2, 2014, 9:57:23 AM5/2/14
to web...@googlegroups.com
This is very helpful, Richard. I have about 20 fields so I think I would have to iterate through the fields and insert the request.vars to the database.

Ahhh after looking at your code it looks like that could would write a record from one table to another. In this case I just want to copy a record from the same table and insert the record as a new ID.

I think the answer will be a combination of your and Oli's approach.

LoveWeb2py

unread,
May 2, 2014, 10:18:41 AM5/2/14
to web...@googlegroups.com
Basically... right now I have a magnifying glass, the pencil, and a trash can for my records. I want to add a plus next to each one of my records and when I click on the plus it copies that records values into a new record and creates a new ID.

I can then modify some of the values in the record or keep it the same if I choose. Does that make sense?

Richard Vézina

unread,
May 2, 2014, 11:16:09 AM5/2/14
to web2py-users
Yes, so you want to pas by a transitionnal form with the data preset base on the copied record values, where you can make the change you want before submit the form. So if you have a grid where you can select the record to copy with the icon you want that link to the transitionnal form, you just have to pass the value of the record to the form throught out URL vars... You can iter like that :

SQLFORM.grid(..., links=[dict(header='', body=lambda row: A(I(_class='icon some_icon'), _href=URL('transitionnal_form', vars={f: row[f] for f in db.table.fields}))))],)

This part :
{f: row[f] for f in db.table.fields}

Is a dict comprehension...

Then in transitionnal form controller you do something like that :

def transition_form():
    for f, v in request.vars:
        db.table[f].default = v
    form = SQLFORM(db.table, ...)
    ...


Richard

LoveWeb2py

unread,
May 2, 2014, 3:10:15 PM5/2/14
to web...@googlegroups.com
for this part: {f: row[f] for f in db.table.fields}

what do I put for fields... could I just leave it as fields?

LoveWeb2py

unread,
May 2, 2014, 3:16:24 PM5/2/14
to web...@googlegroups.com
I just realized I might be running into problems because I'm using 2.3. I haven't upgraded because the new web2py threw my css off. It looks like you're referencing the virtual fields?

http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Old-style-virtual-fields

If you think I should upgrade i'll make the change, but if I could stick with 2.3 I would prefer to do so

LoveWeb2py

unread,
May 2, 2014, 3:40:53 PM5/2/14
to web...@googlegroups.com
Okay quick update:

I loaded a row into python to test the comprehension.
row = db(db.table.id>0).select().first()

{f: row[f] for f in db.table.fields} prints out the list fine and its exactly how I"d like to prepopulate my field on the transition form. Thank you for getting me this far.

However when I try to type vars={f: row[f] for f in db.table.fields})))] I get invalid syntax and the ^ points to the for in the dict comprehension. When I use regular python it works fine. Any thoughts?

LoveWeb2py

unread,
May 2, 2014, 3:44:13 PM5/2/14
to web...@googlegroups.com
Okay... I think I see the issue. My web2py is running Python 2.6 and my Interpreter is 2.7. dictionary comprehension changed between those versions. I'm going to try and construct a dict comprehension for 2.6 and try it again.

Richard Vézina

unread,
May 2, 2014, 3:59:06 PM5/2/14
to web2py-users
Upgrade to 2.9.5 web2py 2.3 is very old... Consider using 2.7 for python... 


You can adapt

Richard

Richard Vézina

unread,
May 2, 2014, 4:01:03 PM5/2/14
to web2py-users
dict((f, row[f]) for f in db.table.fields)

Richard

LoveWeb2py

unread,
May 2, 2014, 4:01:46 PM5/2/14
to web...@googlegroups.com
Is there a way to force web2py to use 2.7 instead of 2.6? I thought it was using 2.7. Thank you for being so patient.

Richard Vézina

unread,
May 2, 2014, 4:02:29 PM5/2/14
to web2py-users
python2.7 web2py ...

Richard Vézina

unread,
May 2, 2014, 4:03:18 PM5/2/14
to web2py-users
Try with dict() contructor in one of my last email if you want to stay in 2.6

Richard

Austin Taylor

unread,
May 2, 2014, 4:10:25 PM5/2/14
to web...@googlegroups.com
I will definitely upgrade in the upcoming months... but for now I"m stuck with 2.6. Your dict comprehension worked, but now I'm getting an error when I click bthe button saying there are too many values to unpack. I'm guessing this is because I'm using 2.6 again and its something to do with my function:

def transition_form():
   for f, v in rqeuest.vars:
     db.table[f].default = v
form = SQLFORM(db.table)
return dict(form=form)


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/U2ajc9LzVCk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.

Richard Vézina

unread,
May 2, 2014, 4:11:40 PM5/2/14
to web2py-users
**dict(...)

Austin Taylor

unread,
May 2, 2014, 4:15:00 PM5/2/14
to web...@googlegroups.com
return **dict(form=form)? I am sorry I know my questions are noob, but I can't tell you how much I appreciate your help. I've spent two days on this problem.

Austin Taylor

unread,
May 2, 2014, 4:37:56 PM5/2/14
to web...@googlegroups.com
I actually see it trying to return the values in the variables in the URL it says field1='data', field2='data2', but its hanging for some reason...

LoveWeb2py

unread,
May 2, 2014, 5:20:40 PM5/2/14
to web...@googlegroups.com
Web2py admin console has a red line at for f, v in request.vars: and then says too many values to unpack.

my function is def transition_form():

     for f, v in request.vars:
     db.table[f].default = v
 form = SQLFORM(db.table, user_signature=True)
return dict(form=form)

Should I have extra values in the dict method?

Niphlod

unread,
May 3, 2014, 8:47:22 AM5/3/14
to web...@googlegroups.com
request.vars is like a dict. Surely you're hitting that issue :-P

>>> test = dict(a=1,b=2)
>>> for k,v in test:
...    print k, v
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 1 value to unpack
>>>

Add an "iteritems()" and you're good to go

>>> for k,v in test.iteritems():
...     print k,v
...
a 1
b 2

Richard Vézina

unread,
May 4, 2014, 9:10:55 AM5/4/14
to web2py-users
Sorry for miss leading, Niphold is true...

So, 

for f, v in request.vars.iteritmes():

     db.table[f].default = v

--

LoveWeb2py

unread,
May 5, 2014, 8:46:25 AM5/5/14
to web...@googlegroups.com
Richard/Niphold,

Thank you so much. It's almost done. Just getting attribute error now but I am going to try to fix that with exception handling.

<type 'exceptions.AttributeError'> 'str' object has no attribute 'year'

I have a modified_on field which is set to datetime. WHen I comment that out it transfers to the next page with no problem. Any thoughts on how I could fix?

LoveWeb2py

unread,
May 5, 2014, 8:50:03 AM5/5/14
to web...@googlegroups.com
Also,

When I click the submit button in {{=form}} it doesn't actually submit anything. It just doubles the values that are already in the fields and puts them into a list. I think I need to do something like db.insert with a new ID number for the submit button.

Richard Vézina

unread,
May 5, 2014, 9:53:38 AM5/5/14
to web2py-users
Please show code!!

Richard

LoveWeb2py

unread,
May 5, 2014, 10:01:46 AM5/5/14
to web...@googlegroups.com
Hi Richard,

Here is what I have so far:

Controllers:
def user_list():
     grid=SQLFORM.smartgrid(db.users, paginate=20, links_placement='left', _href=URL('transition_form', vars=dict((f, row[f]) for f in db.users.fields))))], user_signature=True)
     return dict(grid=grid)


def transition_form():
     for f, v in request.vars:
     db.table[f].default = v
 form = SQLFORM(db.table, user_signature=True)
return dict(form=form)

View:
user_list.html
{{=form}}

This properly populates the values. but it isn't submitting properly. After the form submits I would like it to return to the database and show me the user that was just added. Also, I set my database to autoincrement the ID which should solve the "id problem"

I was thinking I could set something in my transition_form function that if form.process().accepted: redirect(URL('user_list')), but I get an error saying table object has no attribute '_formkey' does this mean I need to do some type of form validation?

LoveWeb2py

unread,
May 5, 2014, 10:03:11 AM5/5/14
to web...@googlegroups.com
Sorry forgot to add .iteritems(): this is the most updated version.


On Monday, May 5, 2014 10:01:46 AM UTC-4, LoveWeb2py wrote:
Hi Richard,

Here is what I have so far:

Controllers:
def user_list():
     grid=SQLFORM.smartgrid(db.users, paginate=20, links_placement='left', _href=URL('transition_form', vars=dict((f, row[f]) for f in db.users.fields))))], user_signature=True)
     return dict(grid=grid)

def transition_form():
     for f, v in request.vars.iteritems():

Richard Vézina

unread,
May 5, 2014, 10:34:28 AM5/5/14
to web2py-users
That what I thought!

How do you validate your form??

Please read the book a bit more about form submission...




def display_form():
   form = SQLFORM(db.person)
   if form.process().accepted:
       response.flash = 'form accepted'
   elif form.errors:
       response.flash = 'form has errors'
   else:
       response.flash = 'please fill out the form'
   return dict(form=form)

You need to process the form, see if it validate... You shouldn't have to insert manually your data if you don't need facy thing and form.process().accepted should handle everything for you.

Richard

LoveWeb2py

unread,
May 5, 2014, 10:40:33 AM5/5/14
to web...@googlegroups.com
I've read that, Richard.

When using this I get that error:

def transition_form():
for f, v in request.vars.iteritems():
    db.users[f].default = v
form = SQLFORM(db.users, user_signature=True)

if form.process().accepted:
response.flash = 'form accepted'
return dict(form=form)

Still get the same error :
<type 'exceptions.AttributeError'> 'Table' object has no attribute '_formkey'

Richard Vézina

unread,
May 5, 2014, 11:13:09 AM5/5/14
to web2py-users
You miss this part in what you show me :

   if form.process().accepted:
       response.flash = 'form accepted'
   elif form.errors:
       response.flash = 'form has errors'
   else:
       response.flash = 'please fill out the form'


Avoid using user_signature at the begining, and you can add this more secure thing latter on.

Richard

LoveWeb2py

unread,
May 5, 2014, 11:33:05 AM5/5/14
to web...@googlegroups.com
Still doesn't work. Says I'm missing _formkey. Also worth noting.... right when I get to the form it says 'please fill out the form' as in its processing the else already before it even accepts the data...

Richard Vézina

unread,
May 5, 2014, 11:49:11 AM5/5/14
to web2py-users
Would you please show the exact code, the one for the SQLFORM.grid funciton and the one for the SQLFORM function...

Richard

LoveWeb2py

unread,
May 5, 2014, 11:57:26 AM5/5/14
to web...@googlegroups.com
Controllers:
@auth.requires_login()
def users_list():
    grid=SQLFROM.smartgrid(db.users, paginate=20, links_placement='left',
         links=[dict(header='', body=lambda row: A(I(_class='icon retweet icon-retweet'),

         _href=URL('transition_form', vars=dict((f, row[f]) for f in db.users.fields))))], user_signature=True)
    return dict(grid=grid)

@auth.requires_login()

def transition_form():
    for f, v in request.vars.iteritems():
       db.users[f].default = v
    form = SQLFORM(db.users)

    if form.process().accepted:
       response.flash = 'form accepted'
    elif form.errors:
        response.flash = 'errors on page'
    else:
        response.flash = 'facepalm'

    return dict(form=form)

It populates the transition_form properly it just doesn't insert the new record when I click submit. It just doubles the record and returns the response in the view. Also, when loading the transition_form page it automatically flashes with 'facepalm' which means its processing the form on load.

Richard Vézina

unread,
May 5, 2014, 12:12:29 PM5/5/14
to web2py-users
You got 'facepalm' because it's not process the form when you get redirected... Since you don't redirect once the form get accepted and process web2py return the same function once the form validate and get process. Now maybe you should delete the request.vars once you have assign them as default value... An other issue maybe related to the fact that your vars names are the same of form.vars... I had issue with name collision in the pass deleting the request.vars after iteratio on it may help.

Richard


--

LoveWeb2py

unread,
May 5, 2014, 12:21:29 PM5/5/14
to web...@googlegroups.com
I tried adding

def transition_form():
    for f, v in request.vars.iteritems():
       db.users[f].default = v
    form = SQLFORM(db.users)
    response.vars = ''

    if form.process().accepted:
       response.flash = 'form accepted'
       redirect(URL('users_list'))
    elif form.errors:
        response.flash = 'errors on page'
    else:
        response.flash = 'facepalm'

    return dict(form=form)

but the same issue of 'Table' object has no attribute '_formkey' still exist. I checked with firebug and the _formkey is under hidden values so it is posting, but for some reason the page isn't picking it up...

LoveWeb2py

unread,
May 5, 2014, 12:27:16 PM5/5/14
to web...@googlegroups.com
I created a clean function and removed the      "for f, v in request.vars.iteritems():db.users[f].default = v" and the form works fine and properly redirects upon submit. So it has to be something with the for loop?
def transition_form():

    form = SQLFORM(db.users)
    response.vars = ''
    if form.process().accepted:
       response.flash = 'form accepted'
       redirect(URL('users_list'))
    elif form.errors:
        response.flash = 'errors on page'
    else:
        response.flash = 'facepalm'

    return dict(form=form)

LoveWeb2py

unread,
May 5, 2014, 12:59:39 PM5/5/14
to web...@googlegroups.com
I figured it out, but its not the most pythonic way of doing things. I had to specify db.users['dictKey'].default = request.vars['dictKey] for all 20 fields.

Again it works, just not sure why the for loop was throwing it off. Thanks so much for your help, Richard!!

Richard Vézina

unread,
May 5, 2014, 1:18:54 PM5/5/14
to web2py-users
do "request.vars.clear()" instead of response.vars = ''

Richard


Reply all
Reply to author
Forward
0 new messages