Parent -> Child Models in a single form

172 views
Skip to first unread message

portly....@googlemail.com

unread,
Sep 3, 2010, 7:38:57 AM9/3/10
to web2py-users
Is it possible to edit a parent + child model as a single form and
automatically create both the parent and respective children in the
database.

As an example, say I have a Person model and the person can have
multiple Addresses. Is it possible to create a Person and add several
addresses on a single form at the same time.

Out of the box with Web2Py I know this is not possible but as it is a
common situation I'm sure someone has already solved this particular
problem.

Many Thanks in advance for any help.

Portly.

Dominic

unread,
Sep 3, 2010, 8:28:26 AM9/3/10
to web2py-users

portly....@googlemail.com

unread,
Sep 3, 2010, 11:14:14 AM9/3/10
to web2py-users
Thank you very much for this Dominic. I've had a quick look and there
is a lot to take in (I guess I was hoping for a much simpler solution
lol).

regards

Portly

On Sep 3, 1:28 pm, Dominic <dominic.koe...@googlemail.com> wrote:
> We (Sahana-Eden) use to do such things with web2py, in connection with
> a RESTful API.
>
> See for example:http://vita.sahanafoundation.org/eden/pr/person/1http://vita.sahanafoundation.org/eden/pr/person/1/address
>
> It can also speak several XML formats, of course, and JSON;http://vita.sahanafoundation.org/eden/pr/person/1.xmlhttp://vita.sahanafoundation.org/eden/pr/person.json
>
> The code behind that looks like:
>
> Person Model:http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%...http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%...
>
> The actual Person controller:http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%...
>
> HTML frontend controller:http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%...
>
> Backend extensions:http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%...
>
> Regards,
> Dominic
>
> On 3 Sep, 13:38, "portly.shor...@googlemail.com"
>
>
>
> <portly.shor...@googlemail.com> wrote:
> > Is it possible to edit a parent + child model as a single form and
> > automatically create both the parent and respective children in the
> > database.
>
> > As an example, say I have a Person model and the person can have
> > multiple Addresses. Is it possible to create a Person and add several
> > addresses on a single form at the same time.
>
> > Out of the box with Web2Py I know this is not possible but as it is a
> > common situation I'm sure someone has already solved this particular
> > problem.
>
> > Many Thanks in advance for any help.
>
> > Portly.- Hide quoted text -
>
> - Show quoted text -

mdipierro

unread,
Sep 3, 2010, 12:38:48 PM9/3/10
to web2py-users
With the new list:string it should be easy to create a widget for it.
WIll look into it.

On Sep 3, 10:14 am, "portly.shor...@googlemail.com"
<portly.shor...@googlemail.com> wrote:
> Thank you very much for this Dominic. I've had a quick look and there
> is a lot to take in (I guess I was hoping for a much simpler solution
> lol).
>
> regards
>
> Portly
>
> On Sep 3, 1:28 pm, Dominic <dominic.koe...@googlemail.com> wrote:
>
> > We (Sahana-Eden) use to do such things with web2py, in connection with
> > a RESTful API.
>
> > See for example:http://vita.sahanafoundation.org/eden/pr/person/1http://vita.sahanafo...
>
> > It can also speak several XML formats, of course, and JSON;http://vita.sahanafoundation.org/eden/pr/person/1.xmlhttp://vita.saha...
>
> > The code behind that looks like:
>
> > Person Model:http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/annotate/head%......

portly....@googlemail.com

unread,
Sep 3, 2010, 2:10:30 PM9/3/10
to web2py-users
Hi Mdipierro

firstly thank you so much for Web2Py - the more I look into it the
more I love it.

I'm slightly confused by your answer however - how would list:string
help me input data for two models at once?

kind regards

Portly

mdipierro

unread,
Sep 3, 2010, 4:14:09 PM9/3/10
to web2py-users
you are right it would not but it may be a way to store multiple
addresses (as a list of strings) without creating a table of
addresses.

On Sep 3, 1:10 pm, "portly.shor...@googlemail.com"

mart

unread,
Sep 3, 2010, 4:39:18 PM9/3/10
to web2py-users
This sounds a lot like sub-forms (ends up being part of the form, but
can be managed separately, even at run time). I worked on Adobe's Form
designer (which is bundled with a full version of Acrobat)... if we we
don't have sub-forms in web2py, I would strongly recommend we create
them :)

Mart

portly....@googlemail.com

unread,
Sep 3, 2010, 6:07:54 PM9/3/10
to web2py-users
I completely agree - one of the really nice things about Django is
that it allows you to have parent -> child models in a single form.

The example from Dominic seems quite complex. Could anyone suggest
some ideas of how we could implement this functionality within Web2Py
- I'm happy to try and code something but as I'm new to Web2Py I'm not
even sure where to start.

any help at all would be appreciated.

Kind Regards

Portly
> > > > > > - Show quoted text -- Hide quoted text -

mart

unread,
Sep 4, 2010, 2:00:29 PM9/4/10
to web2py-users
This a good and interesting problem ;) What I knew about sub-forms was
done using XFA -> xml forms architecture. This was designed to offer
intelligence to forms (I.e. as is, on the web and, of course, in PDF).
But... that was a beast in itself. I'm not too sure how to go about
this with web2py, but web2py is quite the framework in itself and by
having to not only to the Gluon libs but also to python at the first
layer (in the html itself), I'm certain that something just as
fantastic can be achieved. Binding forms to other forms, or there
field data as separate forms should be very do-able. Perhaps looking
into a "container" model would be a way to get there? I.e. container
A contains maybe a form with customer info, where the data entered can
be accessed by container B (defined conditionally) which perhaps
contains another Form in overall customer approval process. Both forms
separate but acting a a single form (each manageable independently
either at the admin level of at the user level (eg. for updates)... ?
Once there adding routing capability should be do-able as well (if not
already featured in web2py).... there are other ways as well, I think
it boiles down to a question of choice and whatever if more efficient
(and whatever integrates the best with Massimo's great framework).

Had I more time, I'd would love take a crack at this (I already need
to find the time for some release/source control related tasks
discussed in a previous thread as well as the crazy workload of my
unending day (and just as crazy) job).

but, IMHO, this is a worthy effort and do hope someone makes something
with this idea!

Mart :)



On Sep 3, 6:07 pm, "portly.shor...@googlemail.com"

geoff

unread,
Sep 8, 2010, 3:08:46 PM9/8/10
to web...@googlegroups.com
Dominic,

Could you give a high level overview of what is going on here and how
you were able to implement the Parent -> Child model in a single form?

Following your links, I wasn't able to discern where/if the input form
was actually accepting values for multiple tables.

I need similar functionality to Portly, and don't really want to go the
iframe route.

Specifically I need to show the 'children' of a table in the same input
form as the parent.

Thanks
Geoff

mdipierro

unread,
Sep 8, 2010, 3:46:25 PM9/8/10
to web2py-users
How about this?

def ListStringWidget(field,value,**attributes):
_id = '%s_%s' % (field._tablename, field.name)
_class = isinstance(field.type,str) and field.type or None
_name = field.name
requires = field.requires
items=[LI(INPUT(_id=_id,_class=_class,_name=_name,value=v)) for v
in value or [''] if v.strip()]
script=SCRIPT("""
// from http://refactormycode.com/codes/694-expanding-input-list-using-jquery
(function(){$.fn.grow_input = function() { return this.each(function()
{ var ul = this;$(ul).find(":text").keypress(function (e) { return
(e.which == ENTER_KEY) ? enter_press(ul) : true;}); }); };
var ENTER_KEY = 13;
function enter_press(ul) { var new_line = make_line(ul);
remove_empty_lines(ul); new_line.appendTo(ul);
new_line.find(":text").focus();
return false;
} function make_line(ul) { var line = $
(ul).find("li:first").clone(true); line.find(':text').val('');
return line;
}
function remove_empty_lines(ul) { $(ul).find("li").each(function()
{var trimmed = jQuery.trim($(this.firstChild).val()); if (trimmed=='')
{ $(this).remove(); } else {$
(this.firstChild).val(trimmed); } }); }
})
();
jQuery(document).ready(function(){jQuery('#
%s_grow_input').grow_input();});
""" % _id)
attributes['_id']=_id+'_grow_input'
return TAG[''](UL(*items,**attributes),script)

db.define_table('person',Field('name'),Field('addresses','list:string',widget=ListStringWidget))

mdipierro

unread,
Sep 8, 2010, 4:27:36 PM9/8/10
to web2py-users

A little better:


def ListStringWidget(field,value,**attributes):
_id = '%s_%s' % (field._tablename, field.name)
_name = field.name
if field.type=='list:integer': _class = 'integer'
else: _class = 'string'
requires = field.requires

items=[LI(INPUT(_id=_id,_class=_class,_name=_name,value=v,hideerror=True))
for v in value or ['']]
#if
items:
# items[-1][0]['hideerror'] =
False
jQuery.fn.grow_input = function()
{
return this.each(function()
{
var ul =
this;
jQuery(ul).find(":text").keypress(function (e) { return (e.which
== 13) ? pe(ul) :
true; });
});
};
function pe(ul)
{
var new_line =
ml(ul);

rel(ul);

new_line.appendTo(ul);

new_line.find(":text").focus();
return
false;
}
function ml(ul)
{
var line =
jQuery(ul).find("li:first").clone(true);

line.find(':text').val('');
return
line;
}
function rel(ul)
{
jQuery(ul).find("li").each(function()
{
var trimmed =
jQuery.trim(jQuery(this.firstChild).val());
if (trimmed=='') jQuery(this).remove(); else
jQuery(this.firstChild).val(trimmed);

geoff

unread,
Sep 8, 2010, 4:29:26 PM9/8/10
to web...@googlegroups.com
Simply dropping this in does not appear to work, I am getting nothing
where the widget ought to be.

In any case, I don't think this is going to work for my case, as a
simply storing mutltiple strings in a single field isn't what I need.

I have another table with ~20 columns.. nutrition information
specifically.

Two types of things have nutrition information, recipes and basic foods.
Basic foods are simple

Name | Type | Nutrition Table Ref

Recipes are quite a bit more complex, but also need to reference the
Nutrtion Table.

Maybe I am just structuring this wrong entirely and should keep the
Nutrition information in the two tables? Since I will have to be
querying the Nutrition table to get both basic Foods and Recipes back, I
think it makes sense to keep the Nutrition information separate.

There is only a one to one correspondence between nutrition information
and another row.. the same row in the nutrition table won't be
referenced by two different rows in either the recipe table or the
basic_foods table.

I hope that this explanation makes clear why I believe your list:string
solution (which is great and I will use else where in this app) does not
solve this particular problem.

Thanks
Geoff

geoff

unread,
Sep 8, 2010, 4:36:09 PM9/8/10
to web...@googlegroups.com
This breaks, I believe formatting is the culprit. I was not able to fix
it right away.

On Wed, 2010-09-08 at 13:27 -0700, mdipierro wrote:

Massimo Di Pierro

unread,
Sep 8, 2010, 4:45:44 PM9/8/10
to web2py-users
perhaps this works

db_list_string.py

mdipierro

unread,
Sep 8, 2010, 4:47:34 PM9/8/10
to web2py-users
To try it. just drop in new empty app under models/ and access the
person table using appadmin.

On Sep 8, 3:45 pm, Massimo Di Pierro <mdipie...@cs.depaul.edu> wrote:
> perhaps this works
>
>  db_list_string.py
> 1KViewDownload
>
>

mdipierro

unread,
Sep 8, 2010, 4:49:25 PM9/8/10
to web2py-users
ps. requires latest trunk code or you may get corrupted data in db.

geoff

unread,
Sep 8, 2010, 4:52:05 PM9/8/10
to web...@googlegroups.com
This works for me now. Indeed it was the formatting. Probably on my
end.

Of course this does not really solve an 'address' issue if an address is
more than one field, which is the case for both myself and the original
poster.

In any case, that is a wonderful widget!

Best,
Geoff

mdipierro

unread,
Sep 8, 2010, 4:52:37 PM9/8/10
to web2py-users
PPS.

perhaps the JS code should go in web2py_ajax.html and we should make
this a default widget for list:integer and list:string types. Do we
need a list:double also?

Massimo

On Sep 8, 3:47 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:

mdipierro

unread,
Sep 8, 2010, 5:05:32 PM9/8/10
to web2py-users
No but this idea can be extended and used to create a more complex
widget using reference fields.

RipRyness

unread,
Sep 9, 2010, 1:25:00 PM9/9/10
to web2py-users
Thinking about this I can't picture it. So do you render the parent-
>child form on the server? If so do you just render inputs for one
child? Or do you pick n number of child forms to render with the
parent?

I've done parent -> child on "one" form. At least it looked that way
to the user. But it was actually two ".load" forms loaded into a
containing .html page using ajax to avoid page refreshes.

-Rip

On Sep 3, 4:07 pm, "portly.shor...@googlemail.com"
Reply all
Reply to author
Forward
0 new messages