Changeset 542
- Timestamp:
- 08/15/07 01:55:04 (1 year ago)
- Files:
-
- pagoda/trunk/Pagoda/pagoda/models/node.py (modified) (2 diffs)
- pagoda/trunk/Pagoda/pagoda/models/revision.py (modified) (2 diffs)
- pagoda/trunk/Pagoda/pagoda/models/revision_mapper.py (modified) (12 diffs)
- pagoda/trunk/Pagoda/pagoda/models/util.py (modified) (1 diff)
- pagoda/trunk/Pagoda/pagoda/plugins/controllers.py (modified) (2 diffs)
- pagoda/trunk/Pagoda/pagoda/plugins/page/models.py (modified) (3 diffs)
- pagoda/trunk/Pagoda/pagoda/plugins/textcontainer/__init__.py (modified) (1 diff)
- pagoda/trunk/Pagoda/pagoda/plugins/textcontainer/models.py (modified) (1 diff)
- pagoda/trunk/Pagoda/pagoda/workflow.py (modified) (2 diffs)
- pagoda/trunk/TestProject/testproject/model.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
pagoda/trunk/Pagoda/pagoda/models/node.py
r541 r542 24 24 25 25 class Node(Revision): 26 def __repr__(self): 27 cls = self.__class__ 28 cols = cls.c.keys() 29 return "%s(%s)" % ( 30 cls.__name__, 31 ", ".join(["%s=%r" % (col, getattr(self, col)) for col in cols]) 32 ) 33 26 34 def query_latest_children(self): 27 35 cls = self.__class__ … … 37 45 parent_id=self.content_id 38 46 ) 39 40 def __repr__(self): 41 cls = self.__class__ 42 cols = cls.c.keys() 43 return "%s(%s)" % ( 44 cls.__name__, 45 ", ".join(["%s=%r" % (col, getattr(self, col)) for col in cols]) 47 48 def delete_node(self, revision_status=workflow.PENDING): 49 return self.new_revision( 50 is_deleted=True, 51 revision_status=revision_status 46 52 ) 47 53 48 assign_mapper(session.context, Node, node_table, inherits=Revision.mapper) 49 54 assign_mapper(session.context, Node, node_table, 55 inherits=Revision.mapper, 56 properties={ 57 'template': relation(Template) 58 } 59 ) pagoda/trunk/Pagoda/pagoda/models/revision.py
r541 r542 20 20 Column('revision_time', DateTime, nullable=False, default=now), 21 21 Column('revision_comment', TEXT, nullable=False, default=""), 22 Column('revision_status', Integer, nullable=False, 23 default=workflow.PENDING 24 ), 22 Column('revision_status', Integer, nullable=False, default=workflow.DRAFT), 25 23 Column('revision_release_time', DateTime, nullable=True), 26 24 Column('revision_expire_time', DateTime, nullable=True) … … 161 159 assign_mapper(session.context, Revision, revision_table, 162 160 inherits=Content.mapper, 163 properties=dict( 164 author=relation(User, lazy=True) 165 ) 161 polymorphic_on=revision_table.c.content_type, 162 properties={ 163 'author': relation(User, lazy=True) 164 } 166 165 ) pagoda/trunk/Pagoda/pagoda/models/revision_mapper.py
r541 r542 35 35 """ 36 36 Generate a `Select` that retrieves matching revisions from 37 ` revisioned_table` correlated with `revision_table`.37 `table` correlated with `self.revision_table`. 38 38 39 39 If `group_by` is a column name, column, or sequence of columns, it 40 will be added to the `Select` - this is necessary for the case of40 will be added to the `Select` -- this is necessary for the case of 41 41 localized tables where it is necessary to group by the locale. 42 42 … … 44 44 `revision_table` joined in this `Select`, to prevent it from being 45 45 confused with the correlated `revision_table`. By default the name 46 of ` revisioned_table` is used and suffixed with '_revision'.46 of `table` is used and suffixed with '_revision'. 47 47 48 48 """ … … 50 50 join_alias = '%s_revision' % table.name 51 51 52 revision_alias = self.revision_table.alias(join_alias) 53 52 revision_table = self.revision_table 53 revision_alias = revision_table.alias(join_alias) 54 54 55 if group_by is not None: 55 56 group_by = util.to_list(group_by) … … 64 65 [max_revision_id], 65 66 and_( 66 table.c.revision_id <= self.revision_table.c.revision_id,67 table.c.revision_id <= revision_table.c.revision_id, 67 68 table.c.revision_id == revision_alias.c.revision_id, 68 self.revision_table.c.content_id == revision_alias.c.content_id69 revision_table.c.content_id == revision_alias.c.content_id 69 70 ), 70 71 from_obj=[table, revision_alias], … … 73 74 correlate=False 74 75 ) 75 revisions.correlate( self.revision_table)76 revisions.correlate(revision_table) 76 77 return revisions 77 78 78 79 def add_table(self, table, id_label=None, locale_column=None, 79 80 join_alias=None): … … 85 86 86 87 subselect = self.revision_subselect(table, locale_column, join_alias) 87 88 88 89 self.tables.add(table) 89 90 self.id_labels[table] = id_label 90 91 self.subselects[table] = subselect 91 92 92 93 def get_selectable(self, alias): 93 94 # XXX: Danger! Alert! Caution! Hey! 94 95 # 95 96 # The order of these tables is important! We want to ensure that the 96 # columns from `content_table` and `revision_table` are selected before97 # others! Not only should their names have precedence, but SQLite's98 # query planner actually returns different results if `revision_table`99 # does not come first in the FROM clause.97 # columns from `content_table` and `revision_table` are selected 98 # before others! Not only should their names have precedence, but 99 # SQLite's query planner actually returns different results if 100 # `revision_table` does not come first in the FROM clause. 100 101 # 101 102 select_tables = [self.content_table, self.revision_table] … … 105 106 for select_table in select_tables: 106 107 # It would be nice to use `select_columns.extend` here. 107 # However, `ColumnCollection.extend` and `ColumnCollection.add` allow108 # later additions to overwrite (and change the order of) existing109 # columns with the same name. We want existing columns to take110 # precedence instead.108 # However, `ColumnCollection.extend` and `ColumnCollection.add` 109 # allow later additions to overwrite (and change the order of) 110 # existing columns with the same name. We want existing columns 111 # to take precedence instead. 111 112 for column in select_table.c: 112 113 if not select_columns.has_key(column.name): … … 121 122 revision_table = self.revision_table 122 123 123 in_clauses = [table.c.revision_id.in_(self.subselects[table]) for124 table in self.tables]125 126 id_clauses = [revision_table.c.revision_id == table.c.revision_id for127 table in self.tables]128 124 in_clauses = [table.c.revision_id.in_(self.subselects[table]) 125 for table in self.tables] 126 127 id_clauses = [revision_table.c.revision_id == table.c.revision_id 128 for table in self.tables] 129 129 130 selectable = select( 130 131 select_columns, 131 132 and_( 132 content_table.c.content_id == revision_table.c.content_id, 133 # content_table.c.content_id == revision_table.c.content_id, 134 133 135 # Ensure that the `revision_id` from `revision_table` matches 134 136 # the `revision_id` from one of the content tables, to prevent 135 # a higher `revision_id` from matching this query but not being 136 # used. 137 or_(*id_clauses), 137 # a higher `revision_id` from matching this query but 138 # not being used. 139 140 # or_(*id_clauses), 138 141 *in_clauses 139 142 ), … … 161 164 """ 162 165 revision_id, content_id, content_locale = args[0] 163 return query.get_by(revision_id=revision_id, content_id=content_id, 164 content_locale=content_locale) 166 return query.get_by( 167 revision_id=revision_id, 168 content_id=content_id, 169 content_locale=content_locale 170 ) 165 171 166 172 def before_insert(self, mapper, connection, instance): … … 177 183 instance.content_type = mapper.local_table.name 178 184 179 # Order of `key_columns` is important due to dependencies!180 key_columns = [181 mapper.c.content_id,182 mapper.c.revision_id,183 mapper.c.node_revision_id,184 mapper.c.generic_revision_id,185 mapper.c.localized_revision_id186 ]187 188 185 insert_tables = util.OrderedSet() 189 186 190 for col in key_columns:187 for col in mapper.primary_key: 191 188 if getattr(instance, col.name) is None: 192 189 insert_table = get_column_table(col) … … 210 207 setattr(instance, column.name, value) 211 208 212 if instance.node_revision_id is None: 213 instance.node_revision_id = instance.revision_id 214 if instance.generic_revision_id is None: 215 instance.generic_revision_id = instance.revision_id 216 if instance.localized_revision_id is None: 217 instance.localized_revision_id = instance.revision_id 209 # Set the labeled `revision_id` foreign keys on `instance`. 210 revision_id = get_original_column(mapper.c.revision_id) 211 for col in mapper.primary_key: 212 # Set instance values only if they are undefined. 213 if getattr(instance, col.name) is None: 214 # If `col` is a foreign key to `revision.revision_id`, set the 215 # corresponding instance value to `revision.revision_id`. 216 if col.foreign_key and follow_foreign_key(col) is revision_id: 217 setattr(instance, col.name, instance.revision_id) 218 218 219 219 # Tell the session that this instance has already been persisted, … … 237 237 else: 238 238 extension = RevisionMapperExtension() 239 extensions.append(extension) # XXX: Testing!239 extensions.append(extension) 240 240 kwargs['extension'] = extensions 241 241 pagoda/trunk/Pagoda/pagoda/models/util.py
r505 r542 2 2 from datetime import datetime 3 3 4 __all__ = ['now', 'get_ column_table', 'follow_foreign_key',5 ' get_instance_values']4 __all__ = ['now', 'get_original_column', 'get_column_table', 5 'follow_foreign_key', 'get_instance_values'] 6 6 7 7 now = datetime.utcnow 8 8 9 def get_original_column(column): 10 return list(column.orig_set)[0] 11 9 12 def get_column_table(column): 10 return list(column.orig_set)[0].table13 return get_original_column(column).table 11 14 12 15 def follow_foreign_key(column): pagoda/trunk/Pagoda/pagoda/plugins/controllers.py
r541 r542 3 3 from turbogears.database import metadata, session 4 4 from turbogears.controllers import Controller 5 from pagoda import config 5 from pagoda import config, workflow 6 6 # Relative imports! 7 7 import models … … 36 36 transaction = models.session.create_transaction() 37 37 try: 38 deleted_content = self.content.new_revision(is_deleted=True) 38 deleted_content = self.content.new_revision( 39 is_deleted=True, revision_status=workflow.PENDING 40 ) 39 41 transaction.commit() 40 42 except models.exceptions.SQLAlchemyError: pagoda/trunk/Pagoda/pagoda/plugins/page/models.py
r534 r542 2 2 from sqlalchemy.ext.assignmapper import assign_mapper 3 3 from turbogears.database import metadata, session 4 from pagoda.models import node_table, Node, Revision4 from pagoda.models import node_table, Content, Revision, Node 5 5 from pagoda.models.revision_mapper import * 6 6 … … 23 23 page_selectable.add_table(node_table) 24 24 page_selectable.add_table(page_generic_table, 'generic_revision_id') 25 page_selectable.add_table(page_localized_table, 'localized_revision_id', 'content_locale') 25 page_selectable.add_table( 26 page_localized_table, 'localized_revision_id', 'content_locale' 27 ) 26 28 27 29 page_table = page_selectable.get_selectable('page') … … 30 32 pass 31 33 32 revision_mapper(session.context, Page, page_table) 34 assign_mapper(session.context, Page, page_table, 35 inherits=Node.mapper, 36 select_table=page_table, 37 polymorphic_identity='page', 38 inherit_condition=or_( 39 page_table.c.revision_id == node_table.c.revision_id, 40 page_table.c.revision_id == page_generic_table.c.revision_id, 41 page_table.c.revision_id == page_localized_table.c.revision_id 42 ) 43 ) pagoda/trunk/Pagoda/pagoda/plugins/textcontainer/__init__.py
r536 r542 1 #from pagoda.plugins.textcontainer.models import *2 #from pagoda.plugins.textcontainer.controllers import *1 from pagoda.plugins.textcontainer.models import * 2 from pagoda.plugins.textcontainer.controllers import * pagoda/trunk/Pagoda/pagoda/plugins/textcontainer/models.py
r537 r542 1 # from sqlalchemy import * 2 # from sqlalchemy.ext.assignmapper import assign_mapper 3 # from turbogears.database import metadata, session 4 # from pagoda.models import Revision 5 # from pagoda.models.revision_mapper import * 6 # 7 # __all__ = ['textcontainer_generic_table', 'textcontainer_localized_table', 8 # 'textcontainer_table', 'TextContainer'] 9 # 10 # textcontainer_generic_table = Table('textcontainer_generic', metadata, 11 # Column('revision_id', None, ForeignKey(Revision.c.revision_id), 12 # primary_key=True 13 # ), 14 # Column('container_name', Unicode(75), nullable=False), 15 # Column('editor_name', String(75), nullable=True) 16 # ) 17 # 18 # textcontainer_localized_table = Table('textcontainer_localized', metadata, 19 # Column('revision_id', None, ForeignKey(Revision.c.revision_id), 20 # primary_key=True 21 # ), 22 # Column('content_locale', String(8), nullable=False), 23 # Column('text', Unicode, nullable=False, default="") 24 # ) 25 # 26 # # textcontainer_table = revisioned_table('textcontainer', 27 # # textcontainer_generic_table, textcontainer_localized_table 28 # # ) 29 # 30 # class TextContainer(Revision): 31 # pass 32 # 33 # # revision_mapper(session.context, TextContainer, textcontainer_table) 1 from sqlalchemy import * 2 from turbogears.database import metadata, session 3 from pagoda.models import Revision 4 from pagoda.models.revision_mapper import * 5 6 __all__ = ['textcontainer_generic_table', 'textcontainer_localized_table', 7 'textcontainer_table', 'TextContainer'] 8 9 textcontainer_generic_table = Table('textcontainer_generic', metadata, 10 Column('revision_id', None, ForeignKey(Revision.c.revision_id), 11 primary_key=True 12 ), 13 Column('container_name', Unicode(75), nullable=False), 14 Column('editor_name', String(75), nullable=True) 15 ) 16 17 textcontainer_localized_table = Table('textcontainer_localized', metadata, 18 Column('revision_id', None, ForeignKey(Revision.c.revision_id), 19 primary_key=True 20 ), 21 Column('content_locale', String(8), nullable=False), 22 Column('text', Unicode, nullable=False, default="") 23 ) 24 25 textcontainer_selectable = RevisionSelectable() 26 textcontainer_selectable.add_table( 27 textcontainer_generic_table, 'generic_revision_id' 28 ) 29 textcontainer_selectable.add_table( 30 textcontainer_localized_table, 'localized_revision_id', 'content_locale' 31 ) 32 33 textcontainer_table = textcontainer_selectable.get_selectable('textcontainer') 34 35 class TextContainer(Revision): 36 pass 37 38 revision_mapper(session.context, TextContainer, textcontainer_table) pagoda/trunk/Pagoda/pagoda/workflow.py
r455 r542 1 1 """ 2 Defines the constants DRAFT, PENDING, APPROVED and DELETED, which are used in2 Defines the constants DRAFT, PENDING, and APPROVED, which are used in 3 3 the `status` column of the `Revision` mapper to indicate the workflow state. 4 4 … … 8 8 PENDING = 1 # The content has been submitted for approval. 9 9 APPROVED = 2 # The content has been approved for publication. 10 DELETED = 3 # The content has been approved for deletion.pagoda/trunk/TestProject/testproject/model.py
r538 r542 2 2 from sqlalchemy import * 3 3 from turbogears.database import metadata, session 4 from sqlalchemy.ext.assignmapper import assign_mapper5 4 from turbogears import identity 6 5 from pagoda.plugins.page import Page … … 32 31 session.flush() 33 32 34 home_page = Page(url=None, parent_id=None, content_locale='en_US', 33 home_page = Page( 34 url=None, parent_id=None, content_locale='en_US', 35 35 title="Home", nav_show=True, revision_author_id=brian.user_id, 36 content_type='page', revision_status=workflow.APPROVED) 36 content_type='page', revision_status=workflow.APPROVED 37 ) 37 38 38 39 session.flush() … … 105 106 # session.flush() 106 107 # 107 108 108 # pagoda_page_revised = Page( 109 109 # content_id=pagoda_page.content_id, … … 113 113 # title="Welcome! (Now typo free.)" 114 114 # ) 115 116 115 # 117 116 # session.flush()
