[Hejes-devel] [923] - blog/index: redirect to index with no args if 0 articles found w/ specified tag or category

hejes-devel at nytud.hu hejes-devel at nytud.hu
Thu Sep 5 15:46:19 CEST 2013


Revision: 923
Author:   mihaltz
Date:     2013-09-05 15:46:19 +0200 (Thu, 05 Sep 2013)
Log Message:
-----------
- blog/index: redirect to index with no args if 0 articles found w/ specified tag or category
- blog/manage: added insert/update/delete callback functions to automatically manage table tags
- blog/manage: tags automatically converted to lower-case
- blog/feed.rss: alpha

Modified Paths:
--------------
    trunk/misc/dbblog/test.py
    trunk/web2py/applications/helyesiras_webdev/controllers/blog.py
    trunk/web2py/applications/helyesiras_webdev/models/dbblog.py

Modified: trunk/misc/dbblog/test.py
===================================================================
--- trunk/misc/dbblog/test.py	2013-09-03 09:33:37 UTC (rev 922)
+++ trunk/misc/dbblog/test.py	2013-09-05 13:46:19 UTC (rev 923)
@@ -18,6 +18,7 @@
 sys.path.append('/opt/web2py')
 from gluon import *
 from gluon.dal import Row
+from gluon.validators import Validator
 
 sys.path.append('../../web2py/applications/helyesiras_webdev/modules')
 import util
@@ -63,7 +64,12 @@
   dbblog.posts.body.requires = IS_NOT_EMPTY()
   dbblog.posts.slug.requires = IS_NOT_EMPTY()
   dbblog.posts.category.requires = IS_IN_DB(dbblog, dbblog.categories.id, '%(name)s')
-  # TODO: posts.image_url.requires = IS_URL?
+  dbblog.posts.tags.requires = IS_LIST_OF(IS_LOWER())
+
+  dbblog.posts._after_update.append( _on_update_posts)
+  dbblog.posts._after_insert.append( _on_insert_posts)
+  dbblog.posts._after_delete.append( _on_delete_posts)
+  dbblog.posts._before_update.append( _bef_upd)
   
   dbblog.commit()
  
@@ -82,10 +88,10 @@
 
 def create_indexes():
   """Create indexes (if they didn't exist) on frequently used columns. Note: tables must already exist (otherwise raises exception)."""
-  create_index_if_not_exists(db, 'images', 'idx_images_title', 'title', True)
-  create_index_if_not_exists(db, 'tags', 'idx_tags_name', 'name', True)
-  create_index_if_not_exists(db, 'categories', 'idx_categories_name', 'name', True)
-  create_index_if_not_exists(db, 'posts', 'idx_posts_created_on', 'created_on')
+  create_index_if_not_exists(dbblog, 'images', 'idx_images_title', 'title', True)
+  create_index_if_not_exists(dbblog, 'tags', 'idx_tags_name', 'name', True)
+  create_index_if_not_exists(dbblog, 'categories', 'idx_categories_name', 'name', True)
+  create_index_if_not_exists(dbblog, 'posts', 'idx_posts_created_on', 'created_on')
   dbblog.commit()
 
 
@@ -96,7 +102,7 @@
 
 
 def add_test_data():
-  dbblog.categories.bulk_insert([{'name': 'Hírek'}, {'name': 'Közönségszolgálat'}, {'name': 'Helyesírási érdekességek'}])
+  #dbblog.categories.bulk_insert([{'name': 'Hírek'}, {'name': 'Közönségszolgálat'}, {'name': 'Helyesírási érdekességek'}])
   now = datetime.datetime.now()
   dbblog.posts.insert(
     slug='elindult-a-blog',
@@ -184,7 +190,103 @@
   posts = dbblog(dbblog.posts.tags.contains(tag)).select(dbblog.posts.ALL)
   print(posts)
 
+def test_set():
+  s = dbblog(dbblog.tags.id == 1289)
+  print(s)
+  print(s.query)
+  print(type(s.query))
+  print(s.query.as_dict())
+  print(s.query.as_json())
+  print(s.query.second)
 
+def _bef_upd(s, f):
+  print('before update: {0}, {1}'.format(s,f))
+  #print(s.select()[0].id)
+  #print(f['title'])
+
+def _aft_upd(s, f):
+  print('after update: {0}, {1}'.format(s,f))
+  print(s.query)
+
+def _on_update_posts(s, f):
+  """Callback functions on update operations on table posts in order to maintain table tags.
+     s: Set object, records updated, f: dictionary, field names and values passed to update
+  """
+  #print('after update: {0}, {1}'.format(s, f))  
+  dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing while we're doing maintenance
+  id = long(s.query.second) # s.select(dbblog.posts.id).first().id # id of post just updated
+  # 1. check whether each new tag is referred to from table tags
+  for tag in f['tags']: # tags just assigned to post
+    r = dbblog(dbblog.tags.name == tag).select() # get matching record from table tags
+    if len(r) == 1: # matching record exists:
+      if id not in r[0].posts: # check if contains reference to post, if not, update it
+        dbblog(dbblog.tags.name == tag).update(posts = r[0].posts + [id])
+    elif len(r) == 0: # no matching record: insert it
+      dbblog.tags.insert(name=tag, posts=[id])
+    #else: error!!! (more than 1 record exists with name==tag)
+  # 2. for each record in table tags that refers to post: check if post still has tag, if not, delete reference/record
+  to_delete = [] # ids of records that have to be deleted from table tags
+  for row in dbblog(dbblog.tags.posts.contains(id)).select():
+    if row.name not in f['tags']:
+      if len(row.posts) > 1:
+        dbblog(dbblog.tags.id == rid).update(posts = [x for x in row.posts if x != id]) # remove reference to post in question
+      else:
+        to_delete.append(row.id) # schedule for deleting
+  for rid in to_delete: # delete
+    dbblog(dbblog.tags.id == rid).delete()
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+
+
+def _on_insert_posts(f, id):
+  """Callback functions on insert operations on table posts in order to maintain table tags.
+     f: a dict of fields passed to insert, id: the id of the newly inserted record
+  """
+  print('after insert: {0}, {1}'.format(f, id))
+  #dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing
+  # Add each tag to table tags
+  for tag in f['tags']:
+    r = dbblog(dbblog.tags.name == tag).select() # get matching record from table tags
+    if len(r) == 1: # matching record exists: update it
+      dbblog(dbblog.tags.name == tag).update(posts = r.first().posts + [id])
+    elif len(r) == 0: # no matching record: insert it
+      dbblog.tags.insert(name=tag, posts=[id])
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+
+
+def _on_delete_posts(s):
+  """Callback functions on insert operations on table posts in order to maintain table tags.
+     s: Set object, records deleted
+  """
+  print('after delete: {0}'.format(s))
+  #dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing while we're doing maintenance
+  id = long(s.query.second) # id of post just deleted (gluon.DAL uses <Set (table.id = id)> for delete/update)
+  print('id of post just deleted: {0}'.format(id))
+  # Delete references from matching records in table tags or delete matching records that only referenced this post
+  to_delete = [] # ids of records that have to be deleted from table tags
+  for row in dbblog(dbblog.tags.posts.contains(id)).select():
+    if len(row.posts) > 1:
+      print('update tags set posts={0} where id={1}'.format([x for x in row.posts if x != id], row.id))
+      dbblog(dbblog.tags.id == row.id).update(posts = [x for x in row.posts if x != id]) # remove reference to post in question
+      dbblog.commit()
+    else:
+      to_delete.append(row.id) # schedule for deleting
+  for rid in to_delete: # delete
+    dbblog(dbblog.tags.id == rid).delete()
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+
+def test_callbacks():
+  #dbblog.posts._before_update.append(lambda s,f: print('before update: {0}, {1}'.format(s,f)))
+  #dbblog.posts._before_update.append( _bef_upd)
+  #dbblog(dbblog.posts.id==1).update(tags=['új verzió'])
+  #dbblog.posts.insert(title='proba', tags=['teszt', 'ablak'])
+  #dbblog(dbblog.posts.id==9).delete()
+  dbblog(dbblog.posts.id==1).update(tags=['új verzió'])
+  #dbblog.commit()
+
+
 #########
 # main
 #########
@@ -193,7 +295,10 @@
 define_tables()
 #create_indexes()
 #add_test_data()
-regenerate_tags_table()
+#regenerate_tags_table()
+#test_set()
+#test_callbacks()
+test_validator()
 
 #query_categories()
 #query_posts()

Modified: trunk/web2py/applications/helyesiras_webdev/controllers/blog.py
===================================================================
--- trunk/web2py/applications/helyesiras_webdev/controllers/blog.py	2013-09-03 09:33:37 UTC (rev 922)
+++ trunk/web2py/applications/helyesiras_webdev/controllers/blog.py	2013-09-05 13:46:19 UTC (rev 923)
@@ -34,6 +34,8 @@
   # prepare pagination
   rset = dbblog(query)
   ntotal = rset.count()
+  if ntotal == 0: # 0 articles found: redirect to index page with no args
+    redirect(URL(c='blog', f='index'))
   perpage = 5
   npages = (ntotal / perpage) + (1 if ntotal % perpage > 0 else 0)
   tmp = safeint(request.vars.get('page'))
@@ -73,6 +75,22 @@
   """Show an SQLFORM.smartgrid to manage dbblog.posts
   """
   grid = SQLFORM.grid(dbblog.posts, orderby=~dbblog.posts.created_on)
-  #grid = SQLFORM.grid(dbblog.posts, left=dbblog.tags.on(dbblog.tags.posts.contains(dbblog.posts.id)))
-  #grid = SQLFORM.smartgrid(dbblog.posts, linked_tables=['tags'])
   return dict(grid=grid)
+  
+
+def feed():
+  """Return a dict that can be rendered by views/generic.rss as the RSS feed of the blog. URL is .../blog/feed.rss"""
+  entries = []
+  posts = dbblog(dbblog.posts.category == dbblog.categories.id).select(orderby=~dbblog.posts.created_on, limitby=(0, 15))
+  for row in posts:
+    post = row.posts
+    entries.append(dict(title='Cim',# post.title,
+                        link=URL(c='blog', f='show', args=[post.slug], host=True),
+                        description='Leiras', #MARKMIN(post.body.split('\n')[0]).xml(),
+                        created_on=str(post.created_on) 
+                        ))
+  return dict(title="Helyesiras.mta.hu blog",
+              link="http://helyesiras.mta.hu/helyesiras/blog",
+              description="A helyesiras.mta.hu oldal hivatalos blogja",
+              entries=entries)
+

Modified: trunk/web2py/applications/helyesiras_webdev/models/dbblog.py
===================================================================
--- trunk/web2py/applications/helyesiras_webdev/models/dbblog.py	2013-09-03 09:33:37 UTC (rev 922)
+++ trunk/web2py/applications/helyesiras_webdev/models/dbblog.py	2013-09-05 13:46:19 UTC (rev 923)
@@ -19,10 +19,80 @@
   return True
 
 
+def _on_update_posts(s, f):
+  """Callback functions on update operations on table posts in order to maintain table tags.
+     s: Set object, records updated, f: dictionary, field names and values passed to update
+  """
+  #print('after update: {0}, {1}'.format(s, f))  
+  dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing while we're doing maintenance
+  id = long(s.query.second) # s.select(dbblog.posts.id).first().id # id of post just updated
+  # 1. check whether each new tag is referred to from table tags
+  for tag in f['tags']: # tags just assigned to post
+    r = dbblog(dbblog.tags.name == tag).select() # get matching record from table tags
+    if len(r) == 1: # matching record exists:
+      if id not in r[0].posts: # check if contains reference to post, if not, update it
+        dbblog(dbblog.tags.name == tag).update(posts = r[0].posts + [id])
+    elif len(r) == 0: # no matching record: insert it
+      dbblog.tags.insert(name=tag, posts=[id])
+    #else: error!!! (more than 1 record exists with name==tag)
+  # 2. for each record in table tags that refers to post: check if post still has tag, if not, delete reference/record
+  to_delete = [] # ids of records that have to be deleted from table tags
+  for row in dbblog(dbblog.tags.posts.contains(id)).select():
+    if row.name not in f['tags']:
+      if len(row.posts) > 1:
+        dbblog(dbblog.tags.id == rid).update(posts = [x for x in row.posts if x != id]) # remove reference to post in question
+      else:
+        to_delete.append(row.id) # schedule for deleting
+  for rid in to_delete: # delete
+    dbblog(dbblog.tags.id == rid).delete()
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+
+
+def _on_insert_posts(f, id):
+  """Callback functions on insert operations on table posts in order to maintain table tags.
+     f: a dict of fields passed to insert, id: the id of the newly inserted record
+  """
+  print('after insert: {0}, {1}'.format(f, id))
+  #dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing
+  # Add each tag to table tags
+  for tag in f['tags']:
+    r = dbblog(dbblog.tags.name == tag).select() # get matching record from table tags
+    if len(r) == 1: # matching record exists: update it
+      dbblog(dbblog.tags.name == tag).update(posts = r.first().posts + [id])
+    elif len(r) == 0: # no matching record: insert it
+      dbblog.tags.insert(name=tag, posts=[id])
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+
+
+def _on_delete_posts(s):
+  """Callback functions on insert operations on table posts in order to maintain table tags.
+     s: Set object, records deleted
+  """
+  print('after delete: {0}'.format(s))
+  #dbblog.executesql('LOCK TABLES tags WRITE, posts READ;') # prevent other sessions from accessing while we're doing maintenance
+  id = long(s.query.second) # id of post just deleted (gluon.DAL uses <Set (table.id = id)> for delete/update)
+  print('id of post just deleted: {0}'.format(id))
+  # Delete references from matching records in table tags or delete matching records that only referenced this post
+  to_delete = [] # ids of records that have to be deleted from table tags
+  for row in dbblog(dbblog.tags.posts.contains(id)).select():
+    if len(row.posts) > 1:
+      print('update tags set posts={0} where id={1}'.format([x for x in row.posts if x != id], row.id))
+      dbblog(dbblog.tags.id == row.id).update(posts = [x for x in row.posts if x != id]) # remove reference to post in question
+      dbblog.commit()
+    else:
+      to_delete.append(row.id) # schedule for deleting
+  for rid in to_delete: # delete
+    dbblog(dbblog.tags.id == rid).delete()
+  dbblog.commit()
+  dbblog.executesql('UNLOCK TABLES;') # remove lock
+  
+# -----------------------------------------------
+
 # Connection to the database (admin)
 dbblog = DAL("mysql://dbblogadmin:d4bl0GGr@localhost/dbhelyesblog")
 
-
 # Define the table names and the fields + add restrictions.
 dbblog.define_table('images',
   Field('file', 'upload'),
@@ -58,11 +128,19 @@
 dbblog.posts.body.requires = IS_NOT_EMPTY()
 dbblog.posts.slug.requires = IS_NOT_EMPTY()
 dbblog.posts.category.requires = IS_IN_DB(dbblog, dbblog.categories.id, '%(name)s')
+dbblog.posts.tags.requires = IS_LIST_OF(IS_LOWER())
 
-dbblog.commit()
-
 # Create indexes (indices?) (if they didn't exist)
 create_index_if_not_exists(dbblog, 'images', 'idx_images_title', 'title', True)
 create_index_if_not_exists(dbblog, 'tags', 'idx_tags_name', 'name', True)
 create_index_if_not_exists(dbblog, 'categories', 'idx_categories_name', 'name', True)
 create_index_if_not_exists(dbblog, 'posts', 'idx_posts_created_on', 'created_on')
+
+# Set callbacks on table posts to automatically maintain table tags
+dbblog.posts._after_update.append( _on_update_posts)
+dbblog.posts._after_insert.append( _on_insert_posts)
+dbblog.posts._after_delete.append( _on_delete_posts)
+
+# make sure everything gets thru (?)
+dbblog.commit()
+




More information about the Hejes-devel mailing list