johnmahugu

web2py notes

Mar 30th, 2015
358
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.32 KB | None | 0 0
  1. Web2py Notes
  2.  
  3. Contents:
  4.  
  5.  
  6. Samples
  7. DAL: Updated DAL Examples, Define Table, Fields, DAL Basics, Validators, DAL Quick Reference, DAL Doctest Examples
  8. FORMs: SQLFORM,CRUD & Manage
  9. Help and Resources
  10. URL Mapping
  11. Clips: Bruno Rocha’s Minimum Layout, Make Download on the Fly
  12. Samples Back to Contents
  13.  
  14. Roll Your Own Layout [from book 6th Edition (pre-release) JUST BEFORE custom layout]
  15.  
  16. Layouts are used to encapsulate page commonality (headers, footers, menus), and though they are not mandatory, they will make your application easier to write and maintain. In particular, we suggest writing layouts that take advantage of the following variables that can be set in the controller. Using these well known variables will help make your layouts interchangeable:
  17.  
  18. response.title
  19. response.subtitle
  20. response.meta.author
  21. response.meta.keywords
  22. response.meta.description
  23. response.flash
  24. response.menu
  25. response.files
  26.  
  27. Except for menu and files, these are all strings and their meaning should be obvious.
  28.  
  29. response.menu menu is a list of 3-tuples or 4-tuples. The three elements are: the link name, a boolean representing whether the link is active (is the current link), and the URL of the linked page. For example:
  30.  
  31. response.menu = [('Google', False, 'http://www.google.com',[]),
  32. ('Index', True, URL('index'), [])]
  33.  
  34. sub-menu
  35.  
  36. The fourth tuple element is an optional sub-menu.
  37.  
  38. response.files is a list of CSS and JS files that are needed by your page.
  39. Joe says this is BIG!
  40. We also recommend that you use:
  41.  
  42. {{include 'web2py_ajax.html'}}
  43.  
  44. in the HTML head, since this will:
  45.  
  46. include the jQuery libraries and
  47. define some backward-compatible JavaScript functions for special effects and Ajax.
  48.  
  49. “web2py_ajax.html” includes:
  50.  
  51. the response.meta tags in the view,
  52. jQuery base,
  53. the calendar datepicker and
  54. all required
  55. CSS and
  56. JS response.files.
  57.  
  58. Style – web2py static css files [see custom layout]
  59.  
  60. There are four static files which are relevant to style:
  61.  
  62. “css/web2py.css” contains web2py specific styles
  63. “css/bootstrap.min.css” contains the Twitter Bootstrap CSS style [bootstrap]
  64. Bootstrap
  65. “css/web2py_bootstrap.css” contains with overrides some Bootstrap styles to conform to web2py needs.
  66. “js/bootstrap.min.js” which includes the libraries for menu effects, modals, panels.
  67.  
  68. Show HTML [see also ]
  69.  
  70. Action
  71.  
  72. def showHTML():
  73. return dict()
  74.  
  75. View
  76.  
  77. <!DOCTYPE html>
  78. <html lang="en">
  79. <head>
  80. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  81. <title>My Title</title>
  82. <link href="css/x.css" rel="stylesheet" />
  83. <script type="text/javascript" src="js/x.js" ></script>
  84. </head>
  85. <body>
  86. <p>Hello from HTML</p>
  87. </body>
  88. </html>
  89.  
  90.  
  91.  
  92. SQLFORM in HTML [see book]
  93.  
  94. Action
  95.  
  96. def display_manual_form():
  97. form = SQLFORM(db.person)
  98. if form.process(session=None, formname='test').accepted:
  99. response.flash = 'form accepted'
  100. elif form.errors:
  101. response.flash = 'form has errors'
  102. else:
  103. response.flash = 'please fill the form'
  104. # Note: no form instance is passed to the view
  105. return dict()
  106.  
  107. View
  108.  
  109. {{extend 'layout.html'}}
  110. <form action="#" enctype="multipart/form-data" method="post">
  111. <ul>
  112. <li>Your name is <input name="name" /></li>
  113. </ul>
  114. <input type="submit" />
  115. <input type="hidden" name="_formname" value="test" />
  116. </form>
  117.  
  118.  
  119. Run from cmd line
  120.  
  121.  
  122.  
  123. cd \web2py python web2py.py -S myappname -M
  124.  
  125. Markmin to html
  126.  
  127. In controllers/default.py
  128.  
  129. def my_action():
  130. my_MM = '''## Sub Menu Structure for Add Table
  131. ### Background
  132. Sub-menus are not appearing in Opera with Web2py v2.3.2.
  133.  
  134. AddTable:
  135. - [[longTableForm %s]]
  136. - [[shortTableForm %s]]
  137. - [[shortTableAndFields %s]]
  138. '''%(URL('default','add_long_tprops'),
  139. URL('default','add_short_tprops'),
  140. URL('default','add_short_tprops_and_fprops'),
  141. )
  142.  
  143. return dict(message=MARKMIN(my_MM))
  144.  
  145. "Choice" Field
  146. Field('sharp_flat_pref', requires = IS_IN_SET(('sharp', 'flat', 'none')),
  147. comment='none->both'),
  148.  
  149. Menu Example
  150.  
  151. response.menu = [
  152. (T('Home'), False, URL('default','index'), []),
  153. (T('ContactUs'), False, URL('default','index'), [
  154. (T('CU-00'), False, URL('default','update_t_contactus00'), []),
  155. (T('CU-01'), False, URL('default','update_t_contactus01'), []),
  156. (T('CU-02'), False, URL('default','update_t_contactus02'), []),
  157. (T('CU-03'), False, URL('default','update_t_contactus03'), []),
  158. (T('CU-04'), False, URL('default','update_t_contactus04'), []),
  159. ]),
  160. ]
  161.  
  162. Email settings for gmail in db.py
  163.  
  164. ## configure email
  165. mail=auth.settings.mailer
  166. mail.settings.server = 'smtp.gmail.com:587'
  167. mail.settings.sender = '[email protected]'
  168. mail.settings.login = '[email protected]:my_pw'
  169.  
  170. owner_id == auth.user_id
  171.  
  172. Field('owner_id', db.auth_user, default=auth.user_id,
  173. readable=False, writable=False),
  174.  
  175. DAL Back to Contents
  176. Updated DAL Examples Back to Contents
  177. Content of Updated DAL Examples
  178.  
  179. Table: Define [a Table], Insert, Select, Update, Count, Delete, Drop [a Table]
  180. Also See in the web2py Book:
  181.  
  182. Other operators
  183. Combining rows
  184. list: and contains
  185.  
  186. Here is the tested Python Code – Enjoy!
  187.  
  188. # make this function now for later result printing
  189. def p(rows):
  190. for r in rows:
  191. print r.name, r.addr, r.city
  192.  
  193. # Content: Define, Insert, Select, Update, Count, Delete, Drop
  194.  
  195. # Define [a Table]
  196. db.define_table('person', Field('name'), Field('addr'), Field('city') ) # person has 4 fields person.id + person.name .addr .city
  197.  
  198. # Insert
  199. db.person.insert( **{'name':'joe', 'addr':'5 Blue St', 'city':'waco'} )
  200. db.person.insert( **{'name':'jim', 'addr':'6 Red St', 'city':'waco'} )
  201. db.person.insert( **{'name':'john', 'addr':'7 Green St', 'city':'waco'} )
  202. db.person.insert( **{'name':'jack', 'addr':'7 Green St', 'city':'houston'} )
  203. db.person.insert( **{'name':'jackie', 'addr':'7 Green St', 'city':'houston'} )
  204. db.person.insert( **{'name':'jill', 'addr':'7 Green St', 'city':'austin'} )
  205. db.person.insert( **{'name':'jane', 'addr':'9 Brown St', 'city':'austin'} )
  206.  
  207.  
  208. # Select
  209. # select all rows in person
  210. rows = db(db.person.id > 0).select()
  211. In [55]: p(rows)
  212. joe 5 Blue St waco
  213. jim 6 Red St waco
  214. john 7 Green St waco
  215. jack 7 Green St houston
  216. jackie 7 Green St houston
  217. jill 7 Green St austin
  218. jane 9 Brown St austin
  219.  
  220. # select rows in city is waco
  221. rows = db(db.person.city == 'waco').select()
  222. In [61]: p(rows)
  223. joe 5 Blue St waco
  224. jim 6 Red St waco
  225. john 7 Green St waco
  226.  
  227. # select rows in city is 'waco' AND addr is '7 Green St'
  228. rows = db( (db.person.city == 'waco') & (db.person.addr == '7 Green St') ).select()
  229. In [73]: p(rows)
  230. john 7 Green St waco
  231.  
  232. # select rows in city is 'houston' OR name is 'joe'
  233. rows = db( (db.person.city == 'houston') | (db.person.name == 'joe') ).select()
  234. In [83]: p(rows)
  235. joe 5 Blue St waco
  236. jack 7 Green St houston
  237. jackie 7 Green St houston
  238.  
  239. # Update -> get an id; do the update
  240. # update 1 update spelling jackie's name to 'jaquay'
  241. id = db( (db.person.name=='jackie') & (db.person.addr=='7 Green St') & (db.person.city=='houston') ).select().first().id
  242. rtn = db.person[id] = dict(name='jaquay', addr='7 Green St', city='houston')
  243.  
  244. # update 1 result
  245. In [87]: rtn
  246. Out[87]: {'addr': '7 Green St', 'city': 'houston', 'name': 'jaquay'}
  247. In [88]: rows = db(db.person.id > 0).select()
  248. In [89]: p(rows)
  249. joe 5 Blue St waco
  250. jim 6 Red St waco
  251. john 7 Green St waco
  252. jack 7 Green St houston
  253. jaquay 7 Green St houston
  254. jill 7 Green St austin
  255. jane 9 Brown St austin
  256.  
  257. # update 2 all '7 Green St's in 'houston' to '7 Yellow St' in 'houston'
  258. rows = db( (db.person.addr=='7 Green St') & (db.person.city=='houston') ).select()
  259. for row in rows:
  260. rtn = db.person[row.id] = dict(addr='7 Yellow St', city='houston')
  261. print rtn
  262. # update 2 result
  263. rows = db(db.person.id > 0).select()
  264. In [94]: p(rows)
  265. joe 5 Blue St waco
  266. jim 6 Red St waco
  267. john 7 Green St waco
  268. jack 7 Yellow St houston
  269. jaquay 7 Yellow St houston
  270. jill 7 Green St austin
  271. jane 9 Brown St austin
  272.  
  273.  
  274. # Count
  275.  
  276. # count 1 items in city is 'houston' OR name is 'joe'
  277. In [97]: print db( (db.person.city == 'houston') | (db.person.name == 'joe') ).count()
  278. 3
  279. # notice relationship to .select()
  280. In [98]: print db( (db.person.city == 'houston') | (db.person.name == 'joe') ).select()
  281. person.id,person.name,person.addr,person.city
  282. 1,joe,5 Blue St,waco
  283. 4,jack,7 Yellow St,houston
  284. 5,jaquay,7 Yellow St,houston
  285.  
  286. # count 2 items where name startswith 'ja'
  287. In [99]: print db( (db.person.name.startswith('ja')) ).count()
  288. 3
  289. In [100]: print db( (db.person.name.startswith('ja')) ).select()
  290. person.id,person.name,person.addr,person.city
  291. 4,jack,7 Yellow St,houston
  292. 5,jaquay,7 Yellow St,houston
  293. 7,jane,9 Brown St,austin
  294.  
  295. # Delete delete all items where name startswith('jo') notice similarity to select()
  296.  
  297. rtn = db( (db.person.name.startswith('jo')) ).delete()
  298. In [105]: print rtn
  299. 2
  300. rows = db(db.person.id > 0).select()
  301. In [107]: p(rows)
  302. jim 6 Red St waco
  303. jack 7 Yellow St houston
  304. jaquay 7 Yellow St houston
  305. jill 7 Green St austin
  306. jane 9 Brown St austin
  307.  
  308.  
  309. # Drop [a Table] drop the table from the db
  310. db.person.drop()
  311.  
  312.  
  313. see_also = '''
  314. [Other operators](http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Other-operators)
  315. [Combining rows](http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Combining-rows)
  316. [list:<type> and contains](http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#list--type--and-contains)
  317. '''
  318. db.define_table() Back to Contents
  319.  
  320. db.define_table()
  321. [see web2py book chap-6 Find “DAL, Table, Field”]
  322.  
  323. Here is a define_table() example
  324. db = DAL('sqlite://storage.db') # db isA DAL instance connected to sqlite database
  325. # The following creates a table object in the DAL object named db
  326. db.define_table('person', Field('name'),Field('age'), format='%(age)s %(name)s %(id)s')
  327. Example Notes:
  328. 1. The id Field is implicitly, an auto-incremented field in each table.
  329. 2. The format table spec, sets the representation for table records. The id field is the default.
  330.  
  331. Here is the define_table() function signature
  332. # from web2py.gluon.dal
  333. define_table(self, tablename, *fields, **args)
  334. Where:
  335. 1. *fields is a list of Field specs
  336. 2. **args is a dict whose keys are in the set TABLE_ARGS
  337. 3. >>> gluon.dal.TABLE_ARGS
  338. set(['polymodel',
  339. 'redefine',
  340. 'on_define',
  341. 'format',
  342. 'migrate',
  343. 'sequence_name',
  344. 'singular',
  345. 'fake_migrate',
  346. 'table_class',
  347. 'common_filter',
  348. 'trigger_name',
  349. 'plural',
  350. 'primarykey'])
  351. format seems to me to be the most important of the TABLE_ARGS
  352.  
  353. Fields Back to Contents
  354.  
  355. Field Constructor Defaults
  356.  
  357. Field(name, 'string', length=None, default=None,
  358. required=False, requires='<default>',
  359. ondelete='CASCADE', notnull=False, unique=False,
  360. uploadfield=True, widget=None, label=None, comment=None,
  361. writable=True, readable=True, update=None, authorize=None,
  362. autodelete=False, represent=None, compute=None,
  363. uploadfolder=os.path.join(request.folder,'uploads'),
  364. uploadseparate=None,uploadfs=None)
  365.  
  366. Field Types Default Field Validators
  367. string IS_LENGTH(length) default length is 512
  368. text IS_LENGTH(65536)
  369. blob None
  370. boolean None
  371. integer IS_INT_IN_RANGE(-1e100, 1e100)
  372. double IS_FLOAT_IN_RANGE(-1e100, 1e100)
  373. decimal(n,m) IS_DECIMAL_IN_RANGE(-1e100, 1e100)
  374. date IS_DATE()
  375. time IS_TIME()
  376. datetime IS_DATETIME()
  377. password None
  378. upload None
  379. reference <table> IS_IN_DB(db,'<table>.id')
  380. list:string None
  381. list:integer None
  382. list:reference <table> IS_IN_DB(db,'<table>.id',multiple=True)
  383.  
  384. Field Notes:
  385.  
  386. To prevent a field from showingin forms: The following indicates that the field “uploader_id” should not be shown in forms, [writable=False] and not even in readonly forms, [readable=False]
  387.  
  388. db.spread.uploader_id.writable = db.spread.uploader_id.readable = False
  389.  
  390. I associate Validators with Fields so I am making Validators part of DAL as opposed to Forms which is the way the Book does it.
  391.  
  392. DAL Basics Back to Contents
  393.  
  394. Here are some basics related to DAL.
  395. Build a Table (DAL, Table, Field objects)
  396.  
  397. db = DAL('sqlite://storage.db') # you can use other db's
  398. db.define_table('person', Field('name')) # person table has 2 fields == person.id & person.name
  399.  
  400. Insert into person table Note: valid id's begin with 1
  401. db.person.insert(name="Alex") # insert person.id == 1
  402. #output:
  403. 1
  404.  
  405. db.person.insert(name="Bob") # insert person.id == 2
  406. #output:
  407. 2
  408.  
  409. db.person.insert(name="Carl") # insert person.id == 3
  410. #output:
  411. 3
  412.  
  413. Query, Set, Rows (The basic web2py DAL objects)
  414.  
  415. person = db.person # var_name 'person' IS_REF_TO Table
  416. name_field = person.name # var_name 'name_field' IS_REF_TO name Field in person Table
  417. q = name_field=='Alex' # build Query using [==, !=, <, >, <=, >=, like, belongs, etc...]
  418. s = db(q) # define a Set (s)
  419. rows = s.select() # fetch records (Rows) from a Set using select()
  420.  
  421. # the rows object allows looping and Field designation
  422. for row in rows:
  423. print row.id, row.name
  424. #output:
  425. 1 Alex
  426.  
  427. # combine above statements into 1
  428. for row in db(db.person.name=='Alex').select():
  429. print row.name
  430. #output:
  431. Alex
  432.  
  433. # select command can take arguments
  434. for row in db().select(db.person.id, db.person.name):
  435. print row.name
  436. #output:
  437. Alex
  438. Bob
  439. Carl
  440.  
  441. # table attribute ALL
  442. for row in db().select(db.person.ALL):
  443. print row.name
  444. #output:
  445. Alex
  446. Bob
  447. Carl
  448.  
  449. # same as ALL different syntax
  450. for row in db(db.person.id > 0).select():
  451. print row.name
  452. #output:
  453. Alex
  454. Bob
  455. Carl
  456.  
  457. Given a single row
  458. row = rows[0]
  459. Here are some syntactic equivalents:
  460. row.name
  461. row['name']
  462. row('person.name') # good for selecting an expression instead of a column.
  463. # all above output:
  464. Alex
  465.  
  466. DAL Shortcuts
  467.  
  468. Quick row select
  469. my_row = db.person[id] #returns the Row with the given id
  470. my_row = db.person(id)
  471. my_row = db.person(db.person.id==id)
  472. # all above are same as:
  473. my_row = db(db.person.id==id).select().first()
  474. my_row = db.person(name='Carl') # non id select
  475.  
  476. Quick delete row
  477. del db.person[id]
  478. # above is same as:
  479. db(db.person.id==id).delete()
  480.  
  481. Quick insert row
  482. db.person[0] = dict(name='Joe')
  483. # above is same as:
  484. db.person.insert(name='Joe')
  485.  
  486. Quick update row
  487. db.person[id] = dict(name='NotJoe')
  488. # above is same as:
  489. db(db.person.id==id).update(name='NotJoe')
  490.  
  491. Recursive select(s)
  492.  
  493. New table “thing” referencing a “person”
  494.  
  495. db.define_table('thing',
  496. Field('name'),
  497. Field('owner','reference person'))
  498. db.thing.insert(name="hammer",owner=1)
  499. db.thing.insert(name="nail",owner=1)
  500. db.thing.insert(name="bell",owner=2)
  501. db.thing.insert(name="clapper",owner=2)
  502. db.thing.insert(name="song",owner=3)
  503. db.thing.insert(name="lyrics",owner=3)
  504.  
  505. select "forward"
  506. things = db(db.thing._id>0).select() #simple select
  507. for thing in things: print thing.name, thing.owner.name
  508. #output:
  509. hammer Alex
  510. nail Alex
  511. bell Bob
  512. clapper Bob
  513. song Carl
  514. lyrics Carl
  515.  
  516. select "backward"
  517. rows = db(db.thing.owner==db.person.id).select(orderby=db.person.name)
  518. for row in rows:
  519. print row.person.name, 'owns', row.thing.name
  520. #output:
  521. Alex owns hammer
  522. Alex owns nail
  523. Bob owns bell
  524. Bob owns clapper
  525. Carl owns song
  526. Carl owns lyrics
  527.  
  528. TODO: Serializing Rows in views
  529.  
  530. Validators Back to Contents
  531.  
  532. As I said before, I associate Validators with Fields so I am making Validators part of DAL as opposed to Forms which is the way the Book does it.
  533. Validator List
  534.  
  535. [see - web2py.gluon.validators ]
  536.  
  537. CLEANUP()
  538.  
  539.  
  540.  
  541. IS_MATCH()
  542.  
  543.  
  544.  
  545. IS_DATE()
  546.  
  547.  
  548.  
  549. IS_DATETIME()
  550.  
  551. IS_DECIMAL_IN_RANGE()
  552.  
  553.  
  554.  
  555. IS_EMAIL()
  556.  
  557.  
  558.  
  559. IS_EMPTY_OR()
  560.  
  561.  
  562.  
  563. IS_EQUAL_TO()
  564.  
  565. IS_EXPR()
  566.  
  567.  
  568.  
  569. IS_FLOAT_IN_RANGE()
  570.  
  571.  
  572.  
  573. IS_GENERIC_URL()
  574.  
  575.  
  576.  
  577. IS_HTTP_URL()
  578.  
  579. IS_IMAGE()
  580.  
  581.  
  582.  
  583. IS_INT_IN_RANGE()
  584.  
  585.  
  586.  
  587. IS_IN_DB()
  588.  
  589.  
  590.  
  591. IS_IN_SET()
  592.  
  593. IS_IPV4()
  594.  
  595.  
  596.  
  597. IS_LENGTH()
  598.  
  599.  
  600.  
  601. IS_LIST_OF()
  602.  
  603.  
  604.  
  605. IS_LOWER()
  606.  
  607. IS_NOT_EMPTY()
  608.  
  609.  
  610.  
  611. IS_NOT_IN_DB()
  612.  
  613.  
  614.  
  615. IS_SLUG()
  616.  
  617.  
  618.  
  619. IS_TIME()
  620.  
  621. IS_UPLOAD_FILENAME()
  622.  
  623.  
  624.  
  625. IS_UPPER()
  626.  
  627.  
  628.  
  629. IS_URL()
  630.  
  631.  
  632. Validator Notes
  633.  
  634. [see Book – Validators] Validators are classes used to validate input fields (including forms generated from database tables).
  635.  
  636. Items listed at the end of Validators in the book:
  637.  
  638. CLEANUP - A Filter - removes all characters whose
  639. decimal ASCII codes are not in the list [10, 13, 32-127]
  640.  
  641. CRYPT - A Filter - performs a secure hash on the input and
  642. it is used to prevent passwords from being passed in the clear to the database.
  643.  
  644. Validator with FORMs:
  645.  
  646. INPUT(_name='a', requires=IS_INT_IN_RANGE(0, 10))
  647.  
  648. Validator with Fields:
  649.  
  650. db.define_table('person', Field('name'))db.person.name.requires = IS_NOT_EMPTY()
  651.  
  652. Multiple Validators:
  653.  
  654. db.person.name.requires = [IS_NOT_EMPTY(), IS_NOT_IN_DB(db, 'person.name')]
  655.  
  656. Override the Default Error Message:
  657.  
  658. db.comment.author.requires = IS_NOT_EMPTY(error_message=T('cannot be empty')
  659.  
  660. DAL Quick Reference Back to Contents::
  661.  
  662. I found the “DAL Quick Reference” and “DAL Doctest Examples referred to here in a post by Iceberg on May 4, 2009 at 9:14 AM on the web2py-users Google group. It is a merged version of the old and new DAL information. I couldn’t find it published anywhere so I published them on this blog, first in a post & now on this page, so I can refer to them. I hope they are beneficial to others.
  663. define_table, insert, count, delete, update
  664.  
  665. db = SQLDB('postgres://user:password@hostname/db', pools=10)
  666. db.define_table('person',db.Field('name','string'))
  667. id= db.person.insert(name='max')
  668. query=(db.person.id==id)
  669. db(query).count()
  670. db(query).delete()
  671. db(query).update(name='Max')
  672. rows = db(query).select(orderby=db.person.name)
  673. for row in rows: print row.name
  674.  
  675. Select Attributes::
  676.  
  677. rows = db(query).select(*fields, orderby=..., left=..., groupby=..., having=..., limitby=..., cache=...)
  678.  
  679. Shortcuts
  680.  
  681. db['person'] ### db.person
  682. db.person['name'] ### db.person.name
  683. db['person']['name'] ### db.person.name
  684. db.person[0]=dict(name='Max') ### insert
  685. db.person[id]=dict(name='Max') ### update by db.person.id
  686. print db.person[id] ### select by db.person.id
  687. del db.person[id] ### delete by db.person.id
  688.  
  689. Truncate and Drop a table::
  690.  
  691. db.person.truncate()
  692. db.person.drop()
  693.  
  694. Reference Fields Inner joins::
  695.  
  696. db.define_table('dog',db.Field('name'))
  697. db.define_table('friendship', db.Field('person',db.person), db.Field('dog',db.dog))
  698. db.friendship.insert(person=id, dog=db.dog.insert(name='Snoopy'))
  699. friends=(db.person.id==db.friendship.person)&(db.dog.id==db.friendship.dog)
  700. rows = db(friends).select(db.person.name, db.dog.name)
  701. for row in rows: print row.person.name, 'is friend of', row.dog.name
  702.  
  703. Left Outer Joins::
  704.  
  705. query=(db.person.id>0)
  706. friends=(db.person.id==db.friendship.person)&(db.dog.id==db.friendship.dog)
  707. rows = db(query).select(db.person.name, db.dog.name, left=db.dog.on(friends))
  708. for row in rows: print row.person.name, 'is friend of', row.dog.name or 'nobody'
  709.  
  710. Complex queries::
  711.  
  712. query = (db.person.id==1)|((db.person.id==2)&(db.person.name=='Max'))
  713. query = (db.person.id==db.friendship.person)&(db.dog.id==db.friendship.dog)
  714. query = db.person.name.lower().like('m%')
  715. query = db.person.id.belongs(('max','Max','MAX'))
  716. query = db.person.birth.year()+1==2008
  717. rows = db(query).select()
  718.  
  719. Nested selects::
  720.  
  721.  
  722.  
  723.  
  724. query = db.person.id.belongs(db()._select(db.friendship.person)
  725.  
  726. Aggregates::
  727.  
  728.  
  729. rows=db(friends).select(db.person.name,db.dog.id.count(),groupby=db.dog.id)
  730.  
  731. Aggregate functions db.table.field.count(), .max(), .min(), sum().
  732. Aliases::
  733.  
  734.  
  735.  
  736.  
  737.  
  738. person=db.person
  739. friendship=db.friendship
  740. puppy=db.dog.with_alias('puppy')
  741. query=(puppy.id==friendhip.dog)&(friendship.person==person.id)
  742. rows=db().select(person.name,puppy.name,left=puppy.on(query))
  743.  
  744. Caching
  745.  
  746.  
  747. rows=db().select(db.person.ALL,cache=(cache.ram,3600))
  748.  
  749. cache=(model,cache_timeout) where model can be cache.ram, cache.disk, cache.memcache or user defined caching model, cache_timeout is in seconds.
  750. CSV Input
  751.  
  752.  
  753. db.person.import_from_csv_file(open(filename,'rb'))
  754.  
  755. CSV Output
  756.  
  757. 1.
  758.  
  759.  
  760.  
  761. str(rows)
  762.  
  763. HTML output
  764.  
  765. 1.
  766.  
  767.  
  768.  
  769. print rows.xml()
  770.  
  771. Set field validators
  772.  
  773. 1.
  774. 2.
  775.  
  776.  
  777.  
  778. db.person.name.requires=IS_NOT_IN_DB(db,db.person.name)
  779. db.friendship.person.requires=IS_IN_DB(db,db.person.id,'%(name)s')
  780.  
  781. Generate and process a form from a model
  782.  
  783.  
  784. form = SQLFORM(db.friendship)
  785. if form.accepts(request.vars, session): response.flash='record inserted'
  786. elif form.errors: response.flash='form errors'
  787.  
  788. The form can then be displayed in a view with:
  789.  
  790. 1.
  791.  
  792.  
  793.  
  794. {{=form}}
  795.  
  796. SQL + HTML Examples
  797.  
  798. Given
  799.  
  800.  
  801.  
  802.  
  803.  
  804. rows=db().select(db.users.ALL)
  805.  
  806. SQLTABLE(rows) turns the rows into a CSS friendly table
  807. SQLFORM(db.users) makes an input form for users
  808. SQLFORM(db.users,rows[i]) makes an edit form for the user in rows[i]
  809. SQLFORM(db.users,rows[i],deletable=True) makes an edit/delete form for the user in row[i]
  810. SQLFORM(....,fields=['name','email']) allows to specify which fields should be displayed in the form. Only those fields will be validated.
  811. SQLFORM(....,labels=['name':'Your Name']) allows to change the labels of the listed fields.
  812.  
  813. A form=SQLFORM(…) object has one method of practical interest: form.accepts(request.vars,session) that processed the input variables (in request.vars) within the session and returns true if the form is valid, false otherwise. Processed variables are in form.vars and errors are in form.errors. The form is modified accordingly. If the form is accepted, accepts also perform the appropriate insert/update/delete in the database.
  814. Extended usage
  815.  
  816. The DAL API are exposed in web2py models, controllers and views but you can access them anywhere with
  817.  
  818.  
  819.  
  820.  
  821.  
  822. from gluon.sql import *
  823.  
  824. Examples of uri strings for SQLDB
  825.  
  826. sqlite://test.db
  827. mysql://user:password@localhost/database
  828. postgres://user:password@localhost/database
  829. mssql://user:password@host/database
  830. firebird://user:password@server:3050/database
  831. oracle://user:password@database
  832.  
  833. On Migrations
  834.  
  835. Changing the list of fields or field types in a model, triggers an automatic migration, i.e. web2py generates SQL to alter the table accordingly. If the table does not exist it is created. Migration actions are logged in the file sql.log accessibled via the admin/design interface. Migration can be turned off on a per-table basis by passing migrate=False to define_table.
  836. DAL Doctest Examples Back to Contents
  837.  
  838.  
  839.  
  840. >>> db=SQLDB("sqlite://test.db")
  841. >>> #OR db=SQLDB("mysql://username:password@host:port/dbname")
  842. >>> #OR db=SQLDB("postgres://username:password@host:port/dbname")
  843.  
  844. # syntax: SQLField('fieldname','fieldtype',length=32,
  845. # required=False, default=None,
  846. # requires=[IS_EMAIL(error_message='invalid email')])
  847.  
  848. >>> tmp=db.define_table('users',
  849. # But notice that SQLField(...) is depreciated and you'd better use db.Field(...) instead
  850. SQLField('stringfield','string',length=32,required=True),
  851. SQLField('booleanfield','boolean',default=False),
  852. SQLField('passwordfield','password'),
  853. SQLField('textfield','text'),
  854. SQLField('blobfield','blob'),
  855. SQLField('uploadfield','upload'),
  856. SQLField('integerfield','integer'),
  857. SQLField('doublefield','double'),
  858. SQLField('datefield','date',default=datetime.date.today()),
  859. SQLField('timefield','time'),
  860. SQLField('datetimefield','datetime'),
  861. migrate='test_user.table')
  862.  
  863. # Insert a field
  864.  
  865. >>> db.users.insert(stringfield='a',booleanfield=True,
  866. passwordfield='p',textfield='x',blobfield='x',
  867. uploadfield=None, integerfield=5,doublefield=3.14,
  868. datefield=datetime.date(2001,1,1),
  869. timefield=datetime.time(12,30,15),
  870. datetimefield=datetime.datetime(2002,2,2,12,30,15))
  871. 1
  872.  
  873. # Drop the table
  874.  
  875. >>> db.users.drop()
  876.  
  877. # Examples of insert, select, update, delete
  878.  
  879. >>> tmp=db.define_table('person',
  880. SQLField('name'),
  881. SQLField('birth','date'),
  882. migrate='test_person.table')
  883. >>> person_id=db.person.insert(name="Marco",birth='2005-06-22')
  884. >>> person_id=db.person.insert(name="Massimo",birth='1971-12-21')
  885. >>> len(db().select(db.person.ALL))
  886. 2
  887. >>> me=db(db.person.id==person_id).select()[0] # test select
  888. >>> me.name
  889. 'Massimo'
  890. >>> db(db.person.name=='Massimo').update(name='massimo') # test update
  891. >>> db(db.person.name=='Marco').delete() # test delete
  892.  
  893. Update a single record
  894.  
  895. >>> me.update_record(name="Max")
  896. >>> me.name
  897. 'Max'
  898.  
  899. Examples of complex search conditions
  900.  
  901. >>> len(db((db.person.name=='Max')&(db.person.birth<'2003-01-01')).select())
  902. 1
  903. >>> len(db((db.person.name=='Max')|(db.person.birth<'2003-01-01')).select())
  904. 1
  905. >>> me=db(db.person.id==person_id).select(db.person.name)[0]
  906. >>> me.name
  907. 'Max'
  908.  
  909. # Examples of search conditions using extract from date/datetime/time
  910.  
  911. >>> len(db(db.person.birth.month()==12).select())
  912. 1
  913. >>> len(db(db.person.birth.year()>1900).select())
  914. 1
  915.  
  916. Example of usage of NULL
  917.  
  918. >>> len(db(db.person.birth==None).select()) ### test NULL
  919. 0
  920. >>> len(db(db.person.birth!=None).select()) ### test NULL
  921. 1
  922.  
  923. # Examples of search conditions using lower, upper, and like
  924.  
  925. >>> len(db(db.person.name.upper()=='MAX').select())
  926. 1
  927. >>> len(db(db.person.name.like('%ax')).select())
  928. 1
  929. >>> len(db(db.person.name.upper().like('%AX')).select())
  930. 1
  931. >>> len(db(~db.person.name.upper().like('%AX')).select())
  932. 0
  933.  
  934. # orderby, groupby and limitby
  935.  
  936. >>> people=db().select(db.person.name,orderby=db.person.name)
  937. >>> order=db.person.name|~db.person.birth
  938. >>> people=db().select(db.person.name,orderby=order)
  939. >>> people=db().select(db.person.name,orderby=order,groupby=db.person.name)
  940. >>> people=db().select(db.person.name,orderby=order,limitby=(0,100))
  941.  
  942. # Example of one 2 many relation
  943.  
  944. >>> tmp=db.define_table('dog',
  945. SQLField('name'),
  946. SQLField('birth','date'),
  947. SQLField('owner',db.person),
  948. migrate='test_dog.table')
  949. >>> db.dog.insert(name='Snoopy',birth=None,owner=person_id)
  950. 1
  951.  
  952. # A simple JOIN
  953.  
  954. >>> len(db(db.dog.owner==db.person.id).select())
  955. 1
  956.  
  957. # Drop tables
  958.  
  959. >>> db.dog.drop()
  960. >>> db.person.drop()
  961.  
  962. # Example of many 2 many relation and SQLSet
  963.  
  964. >>> tmp=db.define_table('author',SQLField('name'),
  965. migrate='test_author.table')
  966. >>> tmp=db.define_table('paper',SQLField('title'),
  967. migrate='test_paper.table')
  968. >>> tmp=db.define_table('authorship',
  969. SQLField('author_id',db.author),
  970. SQLField('paper_id',db.paper),
  971. migrate='test_authorship.table')
  972. >>> aid=db.author.insert(name='Massimo')
  973. >>> pid=db.paper.insert(title='QCD')
  974. >>> tmp=db.authorship.insert(author_id=aid,paper_id=pid)
  975.  
  976. # Define a SQLSet
  977.  
  978. >>> authored_papers=db((db.author.id==db.authorship.author_id)&
  979. (db.paper.id==db.authorship.paper_id))
  980. >>> rows=authored_papers.select(db.author.name,db.paper.title)
  981. >>> for row in rows: print row.author.name, row.paper.title
  982. Massimo QCD
  983.  
  984. # Example of search condition using belongs
  985.  
  986. >>> set=(1,2,3)
  987. >>> rows=db(db.paper.id.belongs(set)).select(db.paper.ALL)
  988. >>> print rows[0].title
  989. QCD
  990.  
  991. # Example of search condition using nested select
  992.  
  993. >>> nested_select=db()._select(db.authorship.paper_id)
  994. >>> rows=db(db.paper.id.belongs(nested_select)).select(db.paper.ALL)
  995. >>> print rows[0].title
  996. QCD
  997.  
  998. # Output in csv
  999.  
  1000. >>> str(authored_papers.select(db.author.name,db.paper.title))
  1001. author.name,paper.title
  1002. Massimo,QCD
  1003.  
  1004. # Delete all leftover tables
  1005.  
  1006. >>> db.authorship.drop()
  1007. >>> db.author.drop()
  1008. >>> db.paper.drop()
  1009.  
  1010. # Commit or rollback your work
  1011.  
  1012. >>> db.commit() # or db.rollback()
  1013.  
  1014. migrate can be False (do not create/alter tables), True (create/alter tables) or a filename (create/alter tables and store migration information in the file).
  1015.  
  1016. Mind there are little idiosyncrasies like the fact that “user” is not a valid field name in PostgreSQL, or the fact that sqlite3 will ignore the type of a field and allow you to put anything in it despite the declared type. Every database backend has its own keywords that may conflict with your tablenames.
  1017. FORMs Back to Contents
  1018. SQLFORM Back to Contents
  1019.  
  1020. [see Book – SQLFORM] The” Good” Book says: “SQLFORM is the single biggest time-saver object in web2py.”
  1021.  
  1022. Here’s a simple SQLFORM MVC example. Given a Model and SQLFORM in a Controller, the Form is automatically generated in the View.
  1023.  
  1024. The Model:
  1025.  
  1026. 1.
  1027. 2.
  1028.  
  1029.  
  1030.  
  1031. db = DAL('sqlite://storage.sqlite')
  1032. db.define_table('person', Field('name', requires=IS_NOT_EMPTY())
  1033.  
  1034. The Controller:
  1035.  
  1036.  
  1037.  
  1038.  
  1039. def display_form():
  1040. form = SQLFORM(db.person)
  1041. if form.accepts(request.vars, session):
  1042. response.flash = 'form accepted'
  1043. elif form.errors:
  1044. response.flash = 'form has errors'
  1045. else:
  1046. response.flash = 'please fill out the form'
  1047. return dict(form=form)
  1048.  
  1049. The generated serialized form in the View:
  1050.  
  1051.  
  1052.  
  1053.  
  1054. <form enctype="multipart/form-data" action="" method="post">
  1055. <table>
  1056. <tr id="person_name__row">
  1057. <td><label id="person_name__label"
  1058. for="person_name">Your name: </label></td>
  1059. <td><input type="text"
  1060. name="name" value="" id="person_name" /></td>
  1061. <td></td>
  1062. </tr>
  1063. <tr id="submit_record__row">
  1064. <td></td>
  1065. <td><input value="Submit" type="submit" /></td>
  1066. <td></td>
  1067. </tr>
  1068. </table>
  1069. <input value="9038845529" type="hidden" name="_formkey" />
  1070. <input value="person" type="hidden" name="_formname" />
  1071. </form>
  1072.  
  1073.  
  1074. Note to Joe -> for examples to include here look in DAL Quick Reference at SQL + HTML Examples. Also look in book “SQLFORM in HTML” & “SQLFORM and Uploads”.
  1075. CRUD & Manage Back to Contents
  1076.  
  1077. see [ book – CRUD ] Here is an example of CRUD usage in a single controller function:
  1078.  
  1079.  
  1080.  
  1081. # assuming db.define_table('person', Field('name'))
  1082. def people():
  1083. form = crud.create(db.person, next=URL('index'),
  1084. message=T("record created"))
  1085. persons = crud.select(db.person, fields=['name'],
  1086. headers={'person.name': 'Name'})
  1087. return dict(form=form, persons=persons)
  1088.  
  1089. Here is another very generic controller function that lets you search, create and edit any records from any table where the tablename is passed request.args(0):
  1090.  
  1091.  
  1092.  
  1093.  
  1094. def manage():
  1095. table=db[request.args(0)]
  1096. form = crud.update(table,request.args(1))
  1097. table.id.represent = lambda id: \
  1098. A('edit:',id,_href=URL(args=(request.args(0),id)))
  1099. search, rows = crud.search(table)
  1100. return dict(form=form,search=search,rows=rows)
  1101.  
  1102. Help and Resources Back to Contents
  1103.  
  1104. Book Official Web2py Book
  1105.  
  1106. All below from google.group.web2py: "Help and Resources" Sticky Post click
  1107. --------------------------------------------------------------------
  1108.  
  1109. Primary source of help: web2py groups
  1110. -------------------------------------
  1111. http://web2py.com/examples/default/usergroups
  1112.  
  1113. Tips on searching the users group
  1114. ---------------------------------
  1115. The search inside the google group does not work very well, instead use:
  1116. http://groups.google.com/groups/advanced_search?safe=off&q=group:web2py
  1117. http://dir.gmane.org/gmane.comp.python.web2py
  1118.  
  1119. Resources
  1120. ---------
  1121.  
  1122. web site http://web2py.com
  1123. demo http://www.web2py.com/demo_admin
  1124. download http://web2py.com/examples/default/download
  1125. docs http://web2py.com/examples/default/documentation
  1126. epydocs http://web2py.com/examples/static/epydoc/index.html
  1127. cheatsheet http://web2py.com/examples/static/web2py_cheatsheet.pdf
  1128. old FAQ http://web2py.com/AlterEgo
  1129. examples http://web2py.com/examples/default/examples
  1130. free apps http://web2py.com/appliances
  1131. plugins http://web2py.com/plugins
  1132.  
  1133. experts http://experts4solutions.com/
  1134.  
  1135. slices http://www.web2pyslices.com/main/default/index
  1136. videos http://vimeo.com (search for web2py)
  1137. chat http://webchat.freenode.net/?channels=web2py
  1138. slides http://www.scribd.com/doc/16085263/web2py-slides-version-1644
  1139. slides http://web2py.com/examples/static/pyworks.pdf (v1.49)
  1140. slides http://web2py.com/examples/static/web2py_presentacion_es.pdf(v1.49 spanish)
  1141. twitter http://twitter.com/web2py
  1142. blip http://web2py.blip.pl/ (polish)
  1143.  
  1144. URL Mapping Back to Contents
  1145.  
  1146. URL Mapping from the Book Chapter 4 – Dispatching. These are the basics there’s more detail in the book.
  1147.  
  1148. The URL http://site.com/a/c/f maps to:
  1149.  
  1150. The function f() in controller “c.py” in application “a“.
  1151.  
  1152. If f is not present, web2py defaults to the index controller function.
  1153. If c is not present, web2py defaults to the default.py controller.
  1154. If a is not present, web2py defaults to the init application.
  1155. If there is no init application, web2py tries to run the welcome application.
  1156. The extension .html is optional.
  1157. The extension .html is assumed as default.
  1158. The extension determines the extension of the view that renders the output of the controller function f().
  1159. The extension allows the same content to be served in multiple formats (html, xml, json, rss, etc.).
  1160.  
  1161. Web2py maps GET/POST requests of the form:
  1162.  
  1163. http://site.com/a/c/f.html/x/y/z?p=1&q=2
  1164.  
  1165. As before, to function f in controller “c.py” in application a
  1166.  
  1167. and it stores the URL parameters in the requestvariable as follows:
  1168.  
  1169. request.args = ['x', 'y', 'z']
  1170. request.vars = {'p':1, 'q':2}
  1171. request.application = 'a'
  1172. request.controller = 'c'
  1173. request.function = 'f'
  1174.  
  1175. request.url = url of request
  1176. request.ajax = False #by default
  1177. if request.ajax == True and wasInitiatedByAWeb2pyComponent:
  1178. request.cid = componentName
  1179.  
  1180. Clips Back to Contents
  1181. Bruno Rocha’s Minimum Layout Back to Contents
  1182.  
  1183. <html>
  1184. <head>
  1185. {{response.files.append(URL(...))}} <!-- Load css/js here -->
  1186. {{include 'web2py_ajax.html'}} <!-- include this here -->
  1187. </head>
  1188.  
  1189. <body>
  1190.  
  1191. <div class="container">
  1192. {{block header}}
  1193. <header> {{=response.title}} </header>
  1194. <!-- blocks create dynamic layouts -->
  1195. {{end}}
  1196.  
  1197. {{include}} <!-- views will be merged here -->
  1198.  
  1199. </div>
  1200.  
  1201. {{block footer}}
  1202. <footer> Copyright 2011 </footer>
  1203. {{end}}
  1204.  
  1205. </body>
  1206. </html>
  1207.  
  1208. Make Download on the Fly Back to Contents
  1209.  
  1210. Thanks to Anthony for answering my question HERE.
  1211.  
  1212. def make_dl():
  1213. import os
  1214.  
  1215. myurl = URL('static', 'excel.txt')
  1216. myfile = os.path.join(request.folder, 'static', 'excel.txt')
  1217. f = open(myfile,'w')
  1218. for i in range(20):
  1219. f.write('This is a test %2s\n'%(i))
  1220. f.close()
  1221.  
  1222. # '?attachment' forces download NOT streaming
  1223. mylink = XML(A('clickme to download',_href=myurl+'?attachment'))
  1224. return dict(mylink=mylink)
Advertisement
Add Comment
Please, Sign In to add comment