Weird problems generating menu from database

312 views
Skip to first unread message

americ...@gmail.com

unread,
Jan 20, 2014, 3:33:50 PM1/20/14
to web...@googlegroups.com

Hi all,

I have been trying for a little over 2 weeks to figure this out...

I'm trying to generate a menu that drops down, I have been able to statically create it by overwriting sample app that has the same drop down menu like the web2py.com site.

I have this in my db.py:
db.define_table('store_catalog',
    Field('maincategory', 'string'),
    Field('subcategory', 'string'),
    Field('description', 'text'))


in my menu.py I have gotten this so far:
response.menu=[]
response.menu.append([T('Catalog'), False, '',
               [(T('%s' % menucatchoice['maincategory']), False, 'link',
                    [(T('%s' % menucatchoice['subcategory']), False, 'link'),]) for menucatchoice in rows ] ])

It gets me a drop down menu except that for each subcategory it repeats adding it to the main category. Let's say there is only 1 main category and 2 subs that go after that
Catalog (this just shows with the caret next to it as intended)
MainCategory
    Sub
    Sub
What I have does put the "Catalog" for the first but, what I get is:
MainCategory
    (blank)
MainCategory(don't want this it's being repeated)
   Subcategory
MainCategory(and this one is also a repeat)
   Subcategory

I have tried to break out the response.menu with so many different .appends it's not funny.  I have also tried adding the "[-1]".  This was the closest I have gotten to what I want it to look like.  I'm at an absolute loss on this, any and all help would be greatly appreciated.

James Burke

unread,
Jan 21, 2014, 1:11:59 AM1/21/14
to web...@googlegroups.com
Hi,

I managed to get one working a little while ago doing this. This has been adapted for your situation, may require some tweaking:

_tables.py - model
db.define_table('store_catelog')


db
.define_table('store_catelog',
   
Field('title', 'string'),
   
Field('description', 'text'),
   
Field('parent_catelog', 'reference store_catelog', default=None),
    format
='%(title)s',
    redefine
=True)

menu.py - model
response.menu = []

categories
= db(db.store_catelog.parent == None).select(orderby=db.store_catelog.id)

for category in categories:    
    response
.menu+=[ (T(category.title), True if active_page == str(category.title.lower()) else False, URL('default','page/%s' % (category.title.lower())), [
       
(T(i.title), True if active_page == str(i.id) else False, URL('default','page/%s' % (i.id)), []) for i in db((db.stored_category.parent == category.id)).select(db.store_category.ALL) if i.parent == category.id
                   
]) ]

The query returns any categories without a parent and adds them to the menu. While doing so looks for any subcategories using the category as a parent.

Hope that helps you out.

-James

americ...@gmail.com

unread,
Jan 21, 2014, 9:35:29 AM1/21/14
to web...@googlegroups.com
I attempted to copy/paste what you have so I can modify it for my needs.  However it immediately errors out with:

AttributeError: 'Table' object has no attribute 'parent'

So I thought I would comment out everything for the menu except response.menu = [] and populate the database (have done this before and the site comes up just no menu as expected).

I then decided to try and populate the database fields.

However when I try to populate it I immediately get an error "IntegrityError: FOREIGN KEY constraint failed". What I did was, put "Animals" for the title, for description I put "Main Animals Category", then for the parent catelog I put "Animals" again.  Upon seeing this I'm confused as to how a subcategory would get identified.  So I also tried just putting "Animals" for the title, and filling in the description as above, but leaving the parent catelog blank, it to also failed with exactly the same error "IntegrityError: FOREIGN KEY constraint failed".  So effectively I'm unable to even put anything in the fields, an issue I never had so I'm unsure what the problem is.

Would it be possible to use the fields I have already established to populate the menu?  Since you have 3 fields identified in your table albeit with slight differences, would it be possible to somehow incorporate that into what I have?  Could you also explain why you used "+=" instead of append?  Maybe I could figure out something from that.

Thanks

Massimo Di Pierro

unread,
Jan 22, 2014, 12:03:16 AM1/22/14
to
First of all notice that if you use web2py2.8.2 you can do this:

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.title)),
    Field('parent_id','reference store_catalog'))

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_trees())

And you get a recursive menu with arbitrary depth and a web interface to edit it with slugs.

web2pygroup

unread,
Jan 21, 2014, 12:05:16 PM1/21/14
to web...@googlegroups.com
I am unable to make it past the point of the database definition.  I put exactly what you have below in my db.py, and in my menu.py I left response.menu=[] so that I could populate the database because the function "def menu_rec" doesn't have anything so I thought to just avoid errors and for simplicity sake start with the db.  However immediately upon attempting to put data in the field with the editor I get the same: "IntegrityError('FOREIGN KEY constraint failed',)"  error message.

Not sure how I can test/incorporate anything with both suggestions causing an error immediately upon clicking submit for simply putting data in the field as is needed.

Yes I am using the latest web2py 2.8.2.

Totally confused because I've never seen any of my database setups act like that and I have a few other tables I setup for the products, etc.  Not a one has ever complained about a "foreign key"...

??????


On Tuesday, January 21, 2014 9:45:27 AM UTC-6, Massimo Di Pierro wrote:
First of all notice that if you use web2py2.8.2 you can do this:

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.title)),
    Field('parent_id','reference store_catalog'))

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_tree())

And you get a recursive menu with arbitrary depth and a web interface to edit it with slugs.

On Tuesday, 21 January 2014 00:11:59 UTC-6, James Burke wrote:

web2pygroup

unread,
Jan 21, 2014, 12:37:10 PM1/21/14
to
My code above seems to only be lacking the proper embedded if conditional statement.  I am able to output the same info I need without repeating it like in this example:

rows = db(db.store_categories).select()
for menucatchoice in rows:
    if menucatchoice['subcategory'] == '':
        print "Main - %s " % menucatchoice['maincategory']
    if menucatchoice['subcategory']:
        print "SubCategory -- %s " % menucatchoice['subcategory']
Which prints out:
Main - Animals
SubCategory -- Dogs
SubCategory -- Cats

Why can't I get it to go like that with my code above?

My code works for seeing what happens.

With the suggested code that isn't working I'm unable to see anything and therefore unable to even debug it since it crashes immediately.

Also I was wondering if there was any actual way to see what MENU helper actually sees, and not just using the shell.  For example when you click on the response in the ticket it shows the menu but doesn't show the actual received output.  When I view that in the shell and make adjustments such as adding/subtracting []] or similar it is difficult to deduce what MENU has determined as a link, url, or whatever.  I have also tried other variations such as:

in menu.py
    response.menu = [T('Catalog'), False, '',[]]
    maininfo=db(db.store_categories.subcategory=='').select(db.store_categories.maincategory)
    for maincat in maininfo:
        response.menu[-1]+=([(T(maincat.maincategory)), False, 'link'])
        for subcat in db(db.store_categories.subcategory!='').select(db.store_categories.subcategory):
            response.menu[-1]+=([[(T(subcat.subcategory)), False, 'link',]])

Which gets me this in the shell:
[<lazyT 'Catalog'>,
 False,
 '',
 [<lazyT 'Animals'>,
  False,
  'link',
  [<lazyT 'Dogs'>, False, 'link'],
  [<lazyT 'Cats'>, False, 'link']]]

And for the astute observer you can see the correct way (i statically created and works):
[(<lazyT 'Catalog'>,
  False,
  '',
  [(<lazyT 'Animals'>,
    False,
    '/beta/default/Animals',
    [(<lazyT 'Dogs'>, False, '/beta/default/Dogs'),
     (<lazyT 'Cats'>, False, '/beta/default/Cats')])])]

You can see the slight differences so obviously I am very close.  For further clarity for myself and anyone else reading this(it has become clear others have tried this extensively), you can see I need to have one less bracket (if I'm correct) removed from in front of the subcategory "Cats" and removed at the end of the subcategory "Dogs".  I had added the [-1] in the slice to correctly do that for the maincategory since it was obvious that the bracket from the response.menu setting at the end needed to be removed.  I also concluded the same thing as you can see for the subcategories.  However it appears that I have something wrong since it doesn't actually remove the brackets at the end of Dogs and beginning of Cats as intended.

I say this because in the "working/correct" version you can clearly see that the last entry "(<lazyT 'Cats'>, False, '/beta/default/Cats')])])]" is missing the bracket that my generated one has "[<lazyT 'Cats'>, False, 'link']]]".  I realize the "()" aren't the same however I noticed that in the shell unless the structure shows correctly as outlined above that it does not work regardless of the "()".  You can also see that the bracket only encompasses the subcategories. 

So I'm wondering how I can get that one bracket out of here from end of Dogs and beginning of Cats (again if I'm correct about the format).  I appreciate all the code samples but, it appears I'm doing something trivially wrong which doesn't seem to suffice replacing the whole thing (in my opinion due to it being one bracket off).

web2pygroup

unread,
Jan 21, 2014, 1:17:19 PM1/21/14
to web...@googlegroups.com
Here's what I've tried so far and here's the results if it helps any to get me on the right track, plus I hope this helps someone else looking for this to because this is something very commonly done in PHP.

I have tried changing this:
response.menu3[-1]+=([[(T(subcat.subcategory)), False, 'link',]])

to this:
response.menu3[-1]+=([(T(subcat.subcategory)), False, 'link',])

Which changes the output in the shell to:

[<lazyT 'Catalog'>,
 False,
 '',
 [<lazyT 'Animals'>,
  False,
  'link',
  <lazyT 'Dogs'>,
  False,
  'link',
  <lazyT 'Cats'>,
  False,
  'link']]

Which obviously isn't correct. 

Continuing:

original:
response.menu3[-1]+=([[(T(subcat.subcategory)), False, 'link',]])

to this:
response.menu3+=([[(T(subcat.subcategory)), False, 'link',]])

Gives this in the shell output:

[<lazyT 'Catalog'>,
 False,
 '',
 [<lazyT 'Animals'>, False, 'link'],
 [<lazyT 'Dogs'>, False, 'link'],
 [<lazyT 'Cats'>, False, 'link']]

Again obviously incorrect.  Continuing:

original:
response.menu3+=([[(T(subcat.subcategory)), False, 'link',]])

changed:
response.menu3[-1]+=((T(subcat.subcategory)), False, 'link',)

Shell output shows:

[<lazyT 'Catalog'>,
 False,
 '',
 [<lazyT 'Animals'>,
  False,
  'link',
  <lazyT 'Dogs'>,
  False,
  'link',
  <lazyT 'Cats'>,
  False,
  'link']]

I tried additional variations but, not sure how much space we have here to keep going with my 2 weeks worth of work.  Essentially the end result is the same a bracket missing to seperate the subcategories.  I've been able to modify and add to lists before, however I've never really experienced a situation where the negative slice appears to be ignored (removing the bracket at the end of dogs and beginning of cats as it is doing for the main category Animals as can be seen), even removed the negative slice ([-1]) for the main categories iteration and when I do it clearly shows that it is actually doing the negative slice properly because the brackets come back at the end of Animals, unlike the subcategories that do not appear to be removing the bracket(s)



On Monday, January 20, 2014 2:33:50 PM UTC-6, web2pygroup wrote:

James Burke

unread,
Jan 21, 2014, 1:29:04 PM1/21/14
to web...@googlegroups.com
Sorry, I had the parent declared as catelog_parent in the table. If you change it to parent it should work ;)

Also += is the same as append.

web2pygroup

unread,
Jan 21, 2014, 1:40:36 PM1/21/14
to web...@googlegroups.com
Getting:

global name 'active_page' is not defined

What did you have for that so I can incorporate it? Or do I even need that since I'm not really caring at the moment about which page they're on (if I understand that variable correctly).  How would I remove it to still achieve the same effect?  Thanks

James Burke

unread,
Jan 21, 2014, 1:52:35 PM1/21/14
to web...@googlegroups.com
You could simply declare it for testing purposes.

Set it to false.

web2pygroup

unread,
Jan 21, 2014, 5:49:50 PM1/21/14
to web...@googlegroups.com
Ok that works, and I'm curious about that variable if you could please explain maybe I could use it and not have to ask to many more questions :)

Also I was wondering how I could incorporate what I had also posted originally -> "([T('
Catalog'), False, ''" <- where this was the heading for the menu then the rest of the items come after it.  So instead of animals being first it would show catalog, then when the user puts the mouse over it drops down showing, animals, etc.

I tried changing the brackets around but to no avail.  Any pointers?  I tried using what I had originally created but all it does is create a seperate "catalog" right next to "animals" on the navbar with "animals" being the only thing doing the drop down.

Thanks again for your code it was nice to see it working unlike mine.

web2pygroup

unread,
Jan 21, 2014, 5:58:39 PM1/21/14
to web...@googlegroups.com
I decided to try and make "Catalog" my first choice in the menu by setting it as the first entry in the DB.  Then I put "Animals" with "Catalog" as its parent, then I added "Dogs" and set that with "Animals" as the parent.

Unfortunately it does not show the "Dogs" category.  Have I possibly done something?  I'm not seeing "Dogs" in the shell when I look at the response.menu...  I do see it in the DB though.

web2pygroup

unread,
Jan 21, 2014, 6:13:13 PM1/21/14
to web...@googlegroups.com
I have also been trying your solution and have gotten to this point, when I try to run the shell to test it errors out immediately with:

AttributeError: 'Rows' object has no attribute 'as_tree'

Any hints on how to fix? Or something else I might try?  I do have the 2.8.2 version..  I noticed when I do a db.store_catalog.<tab key> (within ipython2) I get this as options .as_dict, as_json, .as_xml, .as_yaml.  The only thing I'm familiar with that might be a tree is the .as_xml, is that what you meant?

Thanks for any/all time you can help it's greatly appreciated!


On Tuesday, January 21, 2014 9:45:27 AM UTC-6, Massimo Di Pierro wrote:
First of all notice that if you use web2py2.8.2 you can do this:

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.title)),
    Field('parent_id','reference store_catalog'))

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_tree())

And you get a recursive menu with arbitrary depth and a web interface to edit it with slugs.

On Tuesday, 21 January 2014 00:11:59 UTC-6, James Burke wrote:

web2pygroup

unread,
Jan 21, 2014, 6:25:00 PM1/21/14
to web...@googlegroups.com
Ok figured out I needed to change that to "as_trees".  However the database suggestion you gave is causing a


"IntegrityError: FOREIGN KEY constraint failed"

 error immediately upon trying to put any data into any field.  For example if I put Animals in the title and leave the other field "parent_id" blank it gives me the error.  If I put a number in parent_id with the title an error, and if I just put a number in the parent_id field also an error.

Any ideas?

Thanks


On Tuesday, January 21, 2014 9:45:27 AM UTC-6, Massimo Di Pierro wrote:
First of all notice that if you use web2py2.8.2 you can do this:

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.title)),
    Field('parent_id','reference store_catalog'))

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_tree())

And you get a recursive menu with arbitrary depth and a web interface to edit it with slugs.

On Tuesday, 21 January 2014 00:11:59 UTC-6, James Burke wrote:

Massimo Di Pierro

unread,
Jan 22, 2014, 12:03:46 AM1/22/14
to web...@googlegroups.com
Sorry typo. Let's try again:

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.titl\
e)),
    Field('parent_id','reference store_catalog'))

id1 = db.store_catalog.insert(title='main')
id2 = db.store_catalog.insert(title='one',parent_id=id1)
id3 = db.store_catalog.insert(title='two',parent_id=id2)

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x\
.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_trees())
print response.menu

web2pygroup

unread,
Jan 22, 2014, 1:03:26 PM1/22/14
to web...@googlegroups.com
That works great, thank you!!!  My only remaining question is that when I try to edit the first record "main" in the appadmin I get the foreign key error.  I read here -> https://groups.google.com/forum/#!topic/web2py/klspqXpha4E <- about how to disable it.  Wasn't sure if I should do that or not...  The other records do not act up when changed, just that one so I'm sure I could work around that but, just in case someone else manages the site... I'm not sure.  Thoughts?

web2pygroup

unread,
Jan 23, 2014, 7:40:53 AM1/23/14
to web...@googlegroups.com
After disabling the key constraints none of those errors about it have appeared.  I am grateful for the assistance and will return it anyway I can.  I will post a summary here for anyone attempting this also.  Thanks a million!

web2pygroup

unread,
Jan 29, 2014, 5:39:58 PM1/29/14
to web...@googlegroups.com
Hi again all!

Upon further trying to expand and experiment I stuck at something that maybe I need to be clarified on or I'm doing wrong.

Basically what I did is create a "store.py"  in that I specified the database exactly like it was in db.py (except.  Then what I did in menu.py was simply change:
response.menu = menu_rec(db(db.store_catalog).select().as_trees())

to
response.menu = menu_rec(store(store.store_catalog).select().as_trees())

However it immediately errors out in the shell claiming "store" is not defined, as well as producing a ticket with the same error.  When I change it back to the original "response.menu" and I run the shell I can access store.whatever.  What am I not getting about this or is it not possible?  From the examples I've looked at it seems as though it should work.  Can I get pointed in the right direction or thinking on this please?  Thanks!

Вячеслав Анатольевич

unread,
Jul 27, 2017, 5:39:28 AM7/27/17
to web2py-users

db.define_table('store_catalog',
    Field('title'),
    Field('slug',requires=IS_SLUG(),compute=lambda row: IS_SLUG.urlify(row.titl\
e)),
    Field('parent_id','reference store_catalog'))

id1 = db.store_catalog.insert(title='main')
id2 = db.store_catalog.insert(title='one',parent_id=id1)
id3 = db.store_catalog.insert(title='two',parent_id=id2)

def menu_rec(items): return [(x.title,None,URL('action',args=x.slug),menu_rec(x\
.children)) for x in items or []]
response.menu = menu_rec(db(db.store_catalog).select().as_trees())
print response.menu


Hi! 
Is there a more modern solution to this issue? 
Raises an error - need more than 0 values ​​to unpack
If to substitute  
return [((x.title,None,URL('action',args=x.slug),menu_rec(x.children)) for x in items or []), False, URL('default')]
it shows - but an error

Вячеслав Анатольевич

unread,
Jul 29, 2017, 9:00:40 AM7/29/17
to web2py-users
Hi!
Paraphrase the question, can anyone explain how to create 
a drop-down menu from a database table or show a working example?

Massimo Di Pierro

unread,
Jul 29, 2017, 12:51:38 PM7/29/17
to web2py-users
Let me assume there is only one level and this cannot be arbitrarily nested. Also I assume the initial model of this thread:

db.define_table('store_catalog',
    Field('maincategory', 'string'),
    Field('subcategory', 'string'),
    Field('description', 'text'))

t = store_catalog
rows = db(t).select()
from collections import defaultdict
d=defaultdict(list)
for row in rows: d[row.maincategory].append(row.subcategory)
response.menu = [
    [T(key), False, None, [[T(sub), False, 'link'] for sub in sorted(d[key])]] for key in sorted(d)
]

Вячеслав Анатольевич

unread,
Jul 30, 2017, 2:42:42 AM7/30/17
to web2py-users
Thanks for the answer, Massimo!
But this example makes the menu items in one line with one drop-down menu item.
Like this:

Menuitem Menuitem
- submenuitem - submenuitem


I have three fields, they must be somthing like this (anothermenu - just for example - to understand that is top menu):

<topmenuitem> <anothermenu> <anothermenu> <Log In>
Menuitem
- submenuitem
- subsubmenuitem
- submenuitem
- submenuitem
Menuitem
-submenuitem
-submenuitem
- subsubmenuitem
- subsubmenuitem
- subsubmenuitem
-submenuitem
-submenuitem

Please, can you tell me how to do this?

Dave S

unread,
Jul 31, 2017, 4:36:58 AM7/31/17
to web2py-users
Isn't that a CSS issue, like forms using COL3, etc?

/dps
 

Вячеслав Анатольевич

unread,
Aug 1, 2017, 1:22:51 AM8/1/17
to web2py-users

Hi,  Dave S, maybe you right! But How to create in submenuitem - submenuitem?
 

Dave S

unread,
Aug 1, 2017, 2:37:57 AM8/1/17
to web2py-users


On Monday, July 31, 2017 at 10:22:51 PM UTC-7, Вячеслав Анатольевич wrote:

Hi,  Dave S, maybe you right! But How to create in submenuitem - submenuitem?
 

 Are you using the bootstrap css/js like the welcome app, or the stupic.css stuff from the examples app, or something else?

/dps

Вячеслав Анатольевич

unread,
Aug 1, 2017, 2:49:21 AM8/1/17
to web...@googlegroups.com
I'm using bootstrap css/js form wellcom app, about stupid.css - now reading, but it's a little different,
I need to build a menu from the database table (three fields), as in the example above.
Somthing like this:

topmenu
 |menu - it allways one
 |-sibmenu - it may be about ~20 and more
 |  |- submenu - there can be ~ 100 and more
 

Вячеслав Анатольевич

unread,
Aug 1, 2017, 4:48:05 AM8/1/17
to web...@googlegroups.com
I understood what was the matter, it was styling!
But, how to add the third field:

if auth.is_logged_in():
rows = db(db.map).select(db.map.menu1, db.map.menu2, db.map.mnm_name, orderby=db.map.num, distinct=True)

from collections import defaultdict
d = defaultdict(list)
for row in rows:
d[row.menu1].append(row.menu2)

response.menu = [('Shema', True, URL('default'),[
    [key, False, None, [[sub, False, None, [[sub, False, 'link']]] for sub in sorted(d[key])]] for key in sorted(d)])
]

in layout.html add style and js:

{{=MENU(response.menu, _class='nav navbar-nav web2py-menu web2py-menu-horizontal',
li_class='dropdown', ul_class='dropdown-menu')}}

 <style>
.dropdown-submenu{position:relative;}
.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
.dropdown-submenu:hover>.dropdown-menu{display:block;}
.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
</style>

<script src="{{=URL('static','js/bootstrap-submenu.min.js')}}"></script>

How to add db.map.mnm_name to row.menu2, somthing like that -      

d[row.menu1].append(row.menu2).append(db.map.mnm_name) (i know - that's is not working) 

?????

Вячеслав Анатольевич

unread,
Aug 2, 2017, 2:21:03 AM8/2/17
to web2py-users
Have some idea about this?

Dave S

unread,
Aug 2, 2017, 3:04:05 AM8/2/17
to web2py-users


On Tuesday, August 1, 2017 at 11:21:03 PM UTC-7, Вячеслав Анатольевич wrote:
Have some idea about this?

Me personally, no, but I understand BS3 limits the number of menu levels.

/dps
 

Вячеслав Анатольевич

unread,
Aug 2, 2017, 3:12:04 AM8/2/17
to web2py-users
Me personally, no, but I understand BS3 limits the number of menu levels.

/dps
 

So, it is inpossible or not? I'm ask because it's hard to puzzle over this or it's really impossible?

Dave S

unread,
Aug 2, 2017, 10:55:07 PM8/2/17
to web2py-users

Sorry, outside of my limited knowledge.  I've added and subtracted items from the regular navbar, and I remember a little of the conversation from when the bs3 switch was made, but that's as far as I can go.  For my own purposes, regular A-tags in the left column are what I use, but I rarely have more than 4 places to go from a page.

You need an answer from an actual guru; Massimo himself, or Anthony or Leone, or Michele C (mcm).  Some of the other long-time users maybe, like Richard or Joe.

/dps

Massimo Di Pierro

unread,
Aug 4, 2017, 11:10:34 AM8/4/17
to web2py-users
Yes. It is possible but I am a little confused by your model to be able to provide an example that works for you.

Can you please provide your model again an example of data that should comprise the menu?

Notice what you seek is done here: https://github.com/web2py/web2py/blob/master/gluon/tools.py#L6358 for the wiki menu, where the menu is parsed form the wiki-menu page.

Massimo

Вячеслав Анатольевич

unread,
Aug 6, 2017, 5:31:00 AM8/6/17
to web2py-users
Thanks, Massimo!
So, i have a database table - named "map", in that table - three field - menu1, menu2, mnm_name.
Menu mast be like that:
<top_menu>
   - menu1
        - menu2
              -mnm_name
In menu1 - menu2, in menu2 - mnm_name

Вячеслав Анатольевич

unread,
Aug 7, 2017, 2:00:41 AM8/7/17
to web2py-users
In Wiki menus:
- Home > @////index
- Info > @////info
- web2py > http://www.web2py.com
- - About us > @////aboutus 
- - - Contact us > @////contactus  -  If I add a third minus - THIS NOT WORKED!

Massimo Di Pierro

unread,
Aug 7, 2017, 10:31:30 AM8/7/17
to web2py-users
So I think...

db = DAL('sqlite://storage.sqlite')

db.define_table('map',Field('menu1'),Field('menu2'),Field('mnm_name'),Field('link'))


import collections

def build_menu():

    m1, m2 = [], [] # to preserve orders                                                      

    m = collections.defaultdict(lambda: collections.defaultdict(list))

    for row in db(db.map).select(orderby=db.map.menu1|db.map.menu2):

        if not row.menu1 in m1: m1.append(row.menu1)

        if not row.menu2 in m2: m2.append(row.menu2)

        m[row.menu1][row.menu2].append((row.mnm_name, row.link))

    menu = []

    for a in m1:

        submenu = []

        menu.append([a, None, None, submenu])

        for b, items in m[a].items():

            subsubmenu = [[key, None, link] for key, link in items]

            submenu.append([b, None, None, subsubmenu])

    return menu


response.menu = cache.ram('menu', lambda:build_menu(), None) # to cache it!


Вячеслав Анатольевич

unread,
Aug 14, 2017, 3:50:09 AM8/14/17
to web...@googlegroups.com
Hi Massimo! Thanks so much! It Works! But it generate menu in inline, like this:
menu1     menu1    menu1
In menu1-menu2 in menu2-mnm_name (thats all right) But how menu1 insert in 
response.menu =[
('Main', False, URL('default', 'index'), [here]]

Massimo Di Pierro

unread,
Aug 15, 2017, 10:55:26 PM8/15/17
to web2py-users
Replace:

response.menu = cache.ram('menu', lambda:build_menu(), None) # to cache it!

with

submenu = cache.ram('menu', lambda:build_menu(), None) # to cache it!
response.menu =[('Main', False, URL('default', 'index'), submenu]

Вячеслав Анатольевич

unread,
Aug 16, 2017, 3:04:09 AM8/16/17
to web2py-users

Thank you so much, Massimo!
That's what I need!
Reply all
Reply to author
Forward
0 new messages