One form multiple tables for py4web

350 views
Skip to first unread message

Kevin Keller

unread,
Apr 2, 2021, 10:00:02 AM4/2/21
to py4web
Hello again, 

I also need to create a form that hits multiple related tables. 

Web2py had something need with sqlform.factory:

Is there something similar in py4web? 

I suppose I would have to create my own custom form and custom processing in py4web otherwise. 

Thanks again 

image.png

Andrew Gavgavian

unread,
Apr 2, 2021, 11:46:11 AM4/2/21
to py4web
Multitables were discussed in this py4web live chat. You can see Massimo's response in the transcript here: https://groups.google.com/g/py4web/c/Ff44g5MQGkY/m/yGKIggAkBgAJ

Basically, you can do list comprehension to make a list of all the fields from the table and then when the form is accepted you can manually update the data.

~Andrew

Kevin Keller

unread,
Apr 2, 2021, 3:42:21 PM4/2/21
to Andrew Gavgavian, py4web
Thanks Andrew! One step closer. 

--
You received this message because you are subscribed to the Google Groups "py4web" group.
To unsubscribe from this group and stop receiving emails from it, send an email to py4web+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/py4web/8974b40e-2f31-4c8a-8856-f5e6c60f2ba6n%40googlegroups.com.

Jim Steil

unread,
Apr 8, 2021, 1:38:34 PM4/8/21
to py4web
Kevin

I have some updates I'm going to be submitting for grid.  I've been working with htmx quite a bit and have updated the grid so if you pass an htmx target (just the id of the div to display in) then all activity in the grid happens inside that target.  I think that might help with what you're trying to do.  Any chance you could code up a minimal master/detail app with the functionality you're looking for so I can test to see if I'm on the right track?

I'll submit a PR today, but guessing Massimo will need some pretty strong justification to allow this to happen as it is dependent on a third party tool.  

I didn't embed the link to htmx in the source - if you pass the htmx target to the grid, the grid will live within that div without page reloads.  Still need more testing....

-Jim

Kevin Keller

unread,
Apr 8, 2021, 2:16:49 PM4/8/21
to Jim Steil, py4web
Thanks Jim!

I think I can share something quickly. Just a moment.



Kevin Keller

unread,
Apr 8, 2021, 3:36:37 PM4/8/21
to Jim Steil, py4web
So I just started something like this with 2 grids, but it doesnt actually solve any real world example. 

I was just fooling around with 2 grids. 

One is loaded via yatl and grinder.render() and the other is loaded via component load. 

I was going to actually create a model of a table that makes more sense, but anyhow, you can already see in this proof of concept that if you 
click on the "detail" to add or edit any records there you get redirect to another page (which is of course to be expected), but awkward in this case. 

It would have been better if the redirects stay isolated in that part of the html page and get rendered there too. 

I also have not added the JS conde necessary to load the component automatically depending on which row someone clicks in the master table. 
But that is easy and can be done later.

Screenshot and also the zip file of the PoC I did so far for download from my Google Drive:






image.png
image.png

Kevin Keller

unread,
Apr 8, 2021, 3:39:16 PM4/8/21
to Jim Steil, py4web
Currently the detail table always loads the a product with the id=4 hard coded just for demo purposes, but that is where I would use JS to extract a unique value form the html table row such as id to be able to load the right detail table:

<script>
fetch('https://XXXXXX/calculate/product/4')
         .then(function (response) {
             return response.text();
                                  })
            .then(function (data) {
                appendData(data);
            })
            .catch(function (err) {
                console.log('error: ' + err);
            });
        function appendData(data) {
            var mainContainer = document.getElementById("myData");
           
                var div = document.createElement("div");
                div.innerHTML = data;
                mainContainer.appendChild(div);
           
        }
</script>

Am Do., 8. Apr. 2021 um 20:16 Uhr schrieb Kevin Keller <kell...@gmail.com>:

Kevin Keller

unread,
Apr 8, 2021, 4:10:36 PM4/8/21
to Jim Steil, py4web
Htmx seems to be a slick solution to avoid JS for this :). 



Kevin Keller

unread,
Apr 8, 2021, 5:13:52 PM4/8/21
to Jim Steil, py4web
Deleting already works in place in the detail table. 
For the edit button I think htmx could help to provide inline editing in that row here. 
The details button can probably stay as is, as a redirect to a different page is acceptable when dealing with a lot of additional information that may need to be displayed 
in a detail page. 
The detail page would usually also have some base information from the object or the master table in the upper part of the page. 

Use cases I thinking is the classical invoice app or pizza order app. 

A customer has a customer profile, which has orders, which has invoices. Orders and invoices also have line items as well as other items such as applied discounts and vat. 

A pizza can alse be made of custom ingridients and for some ingridients you pay a premium etc. 




What do you think? 


Jim Steil

unread,
Apr 8, 2021, 6:31:18 PM4/8/21
to py4web
Kevin

I have all the click-to-edit in place and working for one grid.  I'm trying to figure out how to make this all work with a grid that is filtered by a value outside of it's scope.  

Ex

On the edit page for an invoice I want a grid that shows this invoice detail lines.  

It works except that along the way the detail grid loses track of the invoice that it is representing.  I'm thinking about options for the grid to remember and pass along a 'parent' id.  

With your example app I have 2 independent grids working on one page.  Edits happen 'in place' without full page refreshes.  Continuing to work on my above problem.

Let me know if have questions...

Kevin Keller

unread,
Apr 8, 2021, 7:59:34 PM4/8/21
to Jim Steil, py4web
Wow this is amazing. 

I think this is 100% on track for master detail use cases such as passing master information to the edit / detail page of the child row for reference and the inline editing for the detail table row.

Thanks so much for your support and consideration on this.



Jim Steil

unread,
Apr 9, 2021, 4:56:42 PM4/9/21
to py4web
Kevin

Give this link a try:


I kind of mangled your app, but mostly the htmx with multiple grids per page and with parent/child are working.

On the index page I'm displaying two grids, both deferred, using htmx.  (I just saw that I left some code to build the grid in the index route, but it isn't used anywhere)

Both of the grids work and only rebuild the html for the grid, no full page refreshes.

If you click edit on the top grid you will see that it then loads another grid which has the 'child' records (I created a table called product_location that holds these child records).  Once there, you have full CRUD capabilities on the child table while in edit mode on the parent table.

It just occurred to me that I didn't add enough records to test out paging.  I will continue with that.  One problem I am aware of but haven't addressed is if you go into edit mode on the product_location grid that the delete checkbox doesn't work. I have to dig in to that a little bit.  I also may have messed up some filtering, need more testing.  I didn't test column sorting either.

I'm not sure Massimo will accept a PR with what I've done.  I'm using urllib to parse the url in the referer and I'm not sure that is how he would want it done.  This will definitely need refactoring before considering for inclusion in to the main branch.

Oh, to try it out, extract the zip file and then move grid.py into py4web/utils/grid.py, assuming you have pulled the repo from github.

Let me know what you think and what else you run in to.

-Jim

Jim Steil

unread,
Apr 9, 2021, 5:06:31 PM4/9/21
to py4web
One more thing.  Dates/Datetimes don't work yet. To get around that right now you have to override the default data type formatter in grid.

To override for date type:

grid.formatters_by_type["date"] = (lambda value: value.strftime("%m/%d/%Y") if value else "")
grid.formatters_by_type["datetime"] = (lambda value: value.strftime("%m/%d/%Y %H:%M%s") if value else "")

...after you instantiate the grid. 

There is an issue with the way that we format dates with the default formatters_by_type.  I'm working on the issue, you can see it here in stack overflow -> https://stackoverflow.com/questions/66955550/htmx-format-date-for-browser-locale

Hopefully more to come on that soon.  I'd appreciate any help from any javascript gurus, definitely not my forte.

-Jim

Kevin Keller

unread,
Apr 11, 2021, 12:48:17 AM4/11/21
to Jim Steil, py4web
Thank you Jim!

I can't stress how excited I am about this and super grateful.

Sorry for the late reply, unfortunately I got sick with an evil cough and a bit of fever.
I was a bit sick last week already and did a covid test and it was negativ. So shoukd be all good soon. 

But I'll give it a shot today with your app and come back with feedback.

Can't lie in bed doing nothing all day anyway.

Let me think this through too, maybe I. An also find a solution to thr delete button and other challenges you mentioned.


Thank you so much for your help with this.



Kevin Keller

unread,
Apr 11, 2021, 6:38:19 PM4/11/21
to Jim Steil, py4web
I just went over what you have done and I like it a lot. 

For a proper feedback I need to do some thinking. 
I think I will use your code next week use it for a real common case, such as custmers, orders, items, sub-items etc. 

I will set that model up and create some sample data and use your code against it to test how it looks like solving that super common case I think. 

But as a proof of concept what you have done is specatuclar.

We can def. build on that. 

Imagine you can build a CRM or Pizza Order system completely custom within a day with the boilerplate code you have provided without needing to learn javascript for the citizen developer? 

I really think is extremely cool. 



Jim Steil

unread,
Apr 12, 2021, 3:30:11 PM4/12/21
to py4web
Kevin

I too want to do some more testing and develop some samples.

I'm going to be wrapped up in meetings the next couple weeks and won't be getting a lot of time coding, so it won't be soon.  But, I think we're on a good path.

-Jim

Jim Steil

unread,
Apr 15, 2021, 12:51:45 PM4/15/21
to py4web
Here is a little sample app I made showing py4web grid with htmx. The changes allow you to simply make a parent/child grid.  Definitely needs work, but this is where I'm at now. If you're interested in trying it out you need to replace your grid.py in py4web/utils with the one in the root of the sample.  The sample shows:

1. simple py4web grid - products
2. py4web grid with a read-only 'sub-grid' on the edit page - customers
3. py4web/htmx parent-child grid - orders


-Jim

Jim Steil

unread,
Apr 16, 2021, 12:49:53 PM4/16/21
to py4web
I just uploaded a new version

1. htmx delete confirmation fixed
2. added browser back button capability - back button will now remember all clicks in the htmx container and walk you back through them - I'm not sure we want this, but it is currently implemented by default.
3. misc fixes for bulma formatting in grid - I'd updated the wrong place yesterday

Still not production ready but getting better.

I'm curious as to how this compares to the utils.js functions that do trapping similar to web2py components. 

-Jim

Kevin Keller

unread,
Apr 16, 2021, 12:55:43 PM4/16/21
to Jim Steil, py4web
Thanks Jim! 

This is super exciting. 

Is the new version under the same google doc link?

I have some time now to test it. 

:)

Jim Steil

unread,
Apr 16, 2021, 1:03:22 PM4/16/21
to Kevin Keller, py4web
Yes, it should be, I updated the zip and created a new version of it.

Let me know what you find.

Jim

Reply all
Reply to author
Forward
0 new messages