[sqlalchemy] Re: Separate version table
Thanks Arnar, that was interesting to read. I learned a lot with these codes. Here i share current point of my progress. I managed to do mapper extension and document - documentversion objects seems to work ok, but im not so sure, if my solution was very elegant. So if anyone sees this and wants to give further addvises, i'll be glad to hear. My next step is to extend versioned documents from user point to the organisation wide shared documents. # Models from string import join from datetime import datetime class User(object): def __init__(self, name): self.name = name class Organisation(object): def __init__(self, name): self.name = name class Language(object): def __init__(self, alpha2, name): self.alpha2 = alpha2 self.name = name class Document(object): def first(self): return self.versions[0] def latest(self): return self.versions[len(self.versions)-1] class DocumentVersion(object): def __init__(self, name, content, language): self.name = name self.content = content self.language = language class OrganisationDocumentVersion(object): def __init__(self, document_version, user): self.document_version = document_version self.updator = user # Table definitions from connections import engine from sqlalchemy import ForeignKey, MetaData, Table, Column, String, Integer, Unicode, DateTime, Date, Time, Boolean from datetime import datetime METADATA = MetaData() USERS_TABLE = Table(users, METADATA, Column(id, Integer, primary_key=True), Column(name, Unicode(100), nullable=False), ) ORGANISATIONS_TABLE = Table(organisations, METADATA, Column(id, Integer, primary_key=True), Column(name, Unicode(100), nullable=False), ) LANGUAGES_TABLE = Table(languages, METADATA, Column(id, Integer, primary_key=True), Column(alpha2, String(2), unique=True, nullable=False), Column(name, Unicode(100), unique=True, nullable=False), ) DOCUMENTS_TABLE = Table(documents, METADATA, Column(id, Integer, primary_key=True), Column(user_id, Integer, ForeignKey('users.id'), nullable=False), Column(status, Integer, default=1, nullable=False), # 0 = deleted, 1 = active Column(created, DateTime, default=datetime.now()), ) DOCUMENT_VERSIONS_TABLE = Table(document_versions, METADATA, Column(id, Integer, primary_key=True), Column(document_id, Integer, ForeignKey('documents.id'), nullable=False), Column(language_id, Integer, ForeignKey('languages.id'), nullable=False), Column(name, Unicode(64), nullable=False), Column(content, Unicode), Column(version, Integer, default=1, nullable=False), Column(updated, DateTime, default=datetime.now()), Column(status, Integer, default=1, nullable=False), # 0 = deleted, 1 = active ) ORGANISATION_DOCUMENT_VERSIONS = Table(organisation_document_versions, METADATA, Column(organisation_id, Integer, ForeignKey('organisations.id'), primary_key=True), Column(document_version_id, Integer, ForeignKey('document_versions.id'), primary_key=True), Column(user_id, Integer, ForeignKey('users.id'), nullable=False), ) METADATA.create_all(engine) # Mappers from models import * from tables import * from sqlalchemy.orm import mapper, relation, MapperExtension, EXT_PASS, EXT_STOP from datetime import datetime class VersionedDocumentMapperExtension(MapperExtension): def before_update(self, mapper, connection, instance): colvalues = dict([(key, getattr(instance, key)) for key in instance.c.keys()]) del colvalues['id'] colvalues['version'] = instance.version + 1 colvalues['updated'] = datetime.now() # create a new version insert ins = DOCUMENT_VERSIONS_TABLE.insert(colvalues) connection.execute(ins) # get old values select, revert old values to current instance # this prevents making an update for the current instance sel = DOCUMENT_VERSIONS_TABLE.select(DOCUMENT_VERSIONS_TABLE.c.id == instance.id) oldvalues = connection.execute(sel).fetchone() instance.name = oldvalues[name] instance.content = oldvalues[content] instance.language_id = oldvalues[language_id] instance.status = oldvalues[status] return EXT_STOP def before_delete(self, mapper, connection, instance): TODO! Hwo to halt actualy deleting the row? upd = DOCUMENT_TABLE.update(DOCUMENT_TABLE.c.id == instance.document.id)
[sqlalchemy] Re: Separate version table
Thats handy. Where could i get the utils module you're using for Enum datatype? On 28 loka, 23:52, Arnar Birgisson [EMAIL PROTECTED] wrote: On 10/28/07, mmstud [EMAIL PROTECTED] wrote: Thanks there were some good ideas to try. Btw. what does the first def constructor(fun)? It is a decorator I use on mapped classes constructors. It allows me to give keyword arguments to constructors with initial values for any field in class.c (i.e. any mapped columns). cheers, Arnar --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
I dont need history tracking, just revert documents to older ones. that is history, just not timed history. u'll have documents, and then for each document a bunch of versions. Once get it working on simple form, then perhaps trying optimicing and feeding only field, that has changed. Version field automatic update was on my mind lately. Could it be something like this: Column(version, Integer, default=1, nullable=False, onupdate=document_versions.select(document_versions.document_id=c.d ocument_id, order_by=version, order=DESC, limit=1) no idea, what this onupdate is expected to do here? afaik these things are done with a mapper extension, but i'm not sure its the only way. what would be version field? something that counts the inserts for that particular document_id? I just dont know, how to get current document id, is it just c.document_id? yes, yourobj.document_id or whatever u named it as column. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
On 29 loka, 09:08, [EMAIL PROTECTED] wrote: I dont need history tracking, just revert documents to older ones. that is history, just not timed history. Most optimal would it be, if i can make rows with updated fields only, not to copy whole row... but im afraid setting unchanged field to None would be problematic when retrieving versions. I should retrieve several rows and collect the latest not None fields... just pondering u'll have documents, and then for each document a bunch of versions. Once get it working on simple form, then perhaps trying optimicing and feeding only field, that has changed. Version field automatic update was on my mind lately. Could it be something like this: Column(version, Integer, default=1, nullable=False, onupdate=document_versions.select(document_versions.document_id=c.d ocument_id, order_by=version, order=DESC, limit=1) no idea, what this onupdate is expected to do here? It was meant to be oninsert, not onupdate, but on the other hand, if making system with mapper extension, i think i need to do before_update and increase version number there as well as making a new insert and halt doing update. afaik these things are done with a mapper extension, but i'm not sure its the only way. I'm going to try with mapper extension what would be version field? something that counts the inserts for that particular document_id? Yes, just a counter for every insert to document_id. I could use len(Versions) or get latest DocumentVersion.version+1 --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
On 10/29/07, mmstud [EMAIL PROTECTED] wrote: Thats handy. Where could i get the utils module you're using for Enum datatype? The Enum datatype is from the ASPN cookbook, with type bindings for SA. Here's part of my utils module. cheers, Arnar # -*- encoding: UTF-8 -*- import sqlalchemy.types as types import datetime, time from itertools import groupby def numericSort(alist, val=lambda x: x): Returns a copy. See recipe 135435 on aspn def genidx(str): index = [] def _append(fragment, alist=index): if fragment.isdigit(): fragment = int(fragment) alist.append(fragment) prev_isdigit = str[0].isdigit() current_fragment = '' for char in str: curr_isdigit = char.isdigit() if curr_isdigit == prev_isdigit: current_fragment += char else: _append(current_fragment) current_fragment = char prev_isdigit = curr_isdigit _append(current_fragment) return tuple(index) indicies = map(genidx, map(val, alist)) decorated = zip(indicies, alist) decorated.sort() return [item for idx, item in decorated] # From ASPN cookbook, Zoran Isailovski (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486) # Added JSON and SQLAlchemy handles def Enum(*names): ##assert names, Empty enums are not supported # - Don't like empty enums? Uncomment! class EnumClass(types.TypeDecorator): __slots__ = names impl = types.Integer def __iter__(self):return iter(constants) def __len__(self): return len(constants) def __getitem__(self, i): return constants[i] def __repr__(self):return 'Enum' + str(names) def __str__(self): return 'enum ' + str(constants) def convert_bind_param(self, value, engine): return value.Value def convert_result_value(self, value, engine): return self[value] class EnumValue(object): __slots__ = ('__value') def __init__(self, value): self.__value = value Value = property(lambda self: self.__value) EnumType = property(lambda self: EnumType) def __hash__(self):return hash(self.__value) def __cmp__(self, other): if type(other) is str: return cmp(str(self), other) elif type(other) is unicode: return cmp(str(self), str(other)) else: # C fans might want to remove the following assertion # to make all enums comparable by ordinal value {;)) assert self.EnumType is other.EnumType, Only values from the same enum are comparable return cmp(self.__value, other.__value) def __invert__(self): return constants[maximum - self.__value] def __nonzero__(self): return bool(self.__value) def __repr__(self):return str(names[self.__value]) def __json__(self):return str(names[self.__value]) maximum = len(names) - 1 constants = [None] * len(names) for i, each in enumerate(names): val = EnumValue(i) setattr(EnumClass, each, val) constants[i] = val constants = tuple(constants) EnumType = EnumClass() return EnumType class Region(object): def __init__(self, left, top, width, height): self.left = left self.top = top self.width = width self.height = height def __str__(self): return Region(%d,%d,%d,%d) % (self.left,self.top,self.width,self.height) def __repr__(self): return str(self) def countdistinct(iterable, groups=None, key=None): Count things. items = ['red', 'green', 'blue', 'blue'] countdistinct(items) {'blue': 2, 'green': 1, 'red': 1} You can ensure that specific groups are always included in the result, even if they don't occur in the input: items = ['red', 'blue', 'blue'] countdistinct(items, groups=['red', 'green', 'blue']) {'blue': 2, 'green': 0, 'red': 1} The optional `key` argument can be used to provide a function that returns the comparison key for every item: from operator import itemgetter items = [dict(name='foo', category='buzz'), ... dict(name='bar', category='buzz')] print countdistinct(items, key=itemgetter('category')) {'buzz': 2} if groups is None: groups = [] d = dict([(g, 0) for g in groups]) for g, l in groupby(iterable, key=key): d[g] = len(list(l)) + d.get(g, 0) return d --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
Found enumeration implementations: http://www.sqlalchemy.org/trac/wiki/UsageRecipes/Enum http://cheeseshop.python.org/pypi/enum/0.4.3 On 29 loka, 09:04, mmstud [EMAIL PROTECTED] wrote: Thats handy. Where could i get the utils module you're using for Enum datatype? On 28 loka, 23:52, Arnar Birgisson [EMAIL PROTECTED] wrote: On 10/28/07, mmstud [EMAIL PROTECTED] wrote: Thanks there were some good ideas to try. Btw. what does the first def constructor(fun)? It is a decorator I use on mapped classes constructors. It allows me to give keyword arguments to constructors with initial values for any field in class.c (i.e. any mapped columns). cheers, Arnar --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
On 10/29/07, mmstud [EMAIL PROTECTED] wrote: On 29 loka, 09:08, [EMAIL PROTECTED] wrote: I dont need history tracking, just revert documents to older ones. that is history, just not timed history. Most optimal would it be, if i can make rows with updated fields only, not to copy whole row... but im afraid setting unchanged field to None would be problematic when retrieving versions. I should retrieve several rows and collect the latest not None fields... just pondering That reminded me, I have another project that does automatic changelogs. There is something in the ML archives, but here's some more code. I'm afraid all class, variable and field names are in Icelandic - I put in comments with translations where it matters. I also removed alot of auxiliary tables since this is proprietary code. The base entity that keeps a changelog of itself is Verkefni (means project). A changelog entry is generated by calling changelog_entry on a dirty object. This is not done automatically as sometimes one wants to update an object without generating a log entry. Arnar # -*- encoding: UTF-8 -*- import datetime import cherrypy import sqlalchemy from sqlalchemy.ext.sessioncontext import SessionContext from sqlalchemy.ext.assignmapper import assign_mapper from sqlalchemy.orm import MapperExtension, EXT_PASS _engine = None metadata = sqlalchemy.DynamicMetaData() def get_engine(): global _engine dburi = cherrypy.config.get('verkstjorinn.db.uri') encoding = cherrypy.config.get('verkstjorinn.db.encoding', 'utf-8') echo = cherrypy.config.get('verkstjorinn.db.echo', False) if not _engine: _engine = sqlalchemy.create_engine(dburi, encoding=encoding, echo=echo, convert_unicode=True) metadata.connect(_engine) elif not metadata.is_bound(): metadata.connect(_engine) return _engine ctx = SessionContext(lambda:sqlalchemy.create_session(bind_to=get_engine())) def sa_uow_cleanup(): ctx.current.clear() sa_uow_cleanup.failsafe = True cherrypy.tools.sacleanup = cherrypy.Tool('on_end_request', sa_uow_cleanup) class base_model(object): def __repr__(self): props = [] for key in self.c.keys(): props.append(%s=%r % (key, getattr(self, key))) return %s %s % (self.__class__.__name__, ' '.join(props)) from sqlalchemy import * ## Verkefni = Projects verkefni_flokkar = Table(verkefni_flokkar, metadata, Column(verkefni, Integer, ForeignKey(verkefni.verkefni), primary_key=True), Column(flokkur, Integer, ForeignKey(flokkar.flokkur), primary_key=True) ) # No mapper for this table, it's only a join table for the many-to-many relation verkefni = Table(verkefni, metadata, Column(verkefni, Integer, primary_key=True), Column(skrad, DateTime, nullable=False, default=func.now()), Column(sidast_breytt, DateTime, nullable=False, default=func.current_timestamp(), onupdate=func.current_timestamp()), Column(skrad_af, Unicode(20), ForeignKey(notendur.notandi), nullable=False), Column(deadline, Date), Column(titill, Unicode, nullable=False), Column(lysing, Unicode, nullable=False), Column(mikilvaegi, Integer, ForeignKey(mikilvaegi.mikilvaegi), nullable=False, default=40), Column(forgangur, Integer, nullable=False, default=0), Column(framvinda, Integer, nullable=False, default=0), Column(fasi, Integer, ForeignKey(fasar.fasi), nullable=False, default=5), Column(abyrgdarmadur, Unicode(20), ForeignKey(notendur.notandi), nullable=False), Column(cc, Unicode), Column(verknumer, Unicode(20)), Column(tengilidur, Unicode(60)), Column(bidur_eftir, Unicode) ) class Verkefni(base_model): class DEFAULTS: def __init__(self): self.verkefni = 0 self.skrad = datetime.datetime.now() self.sidast_breytt = datetime.datetime.now() self.titill = self.lysing = self.verknumer = None self.tengilidur = None self.deadline = None self.bidur_eftir = None self.flokkar = [] self.mikilvaegi = Mikilvaegi.get(40) self.forgangur = 0 self.framvinda = 0 self.fasi = Fasi.get(5) self.abyrgdarmadur = None # Must be set by controller self.cc = None self.depends_on = () self.depend_on_me = () def get_fyrirtaeki(self): return [] def get_framkvaemd(self): return [] def combined_athugasemdir(self): return [] def get_dependency_parents(self): return [] def get_dependency_children(self): return [] @property def skyldverkefni(self): related = SkyltVerkefni.select_by( or_(SkyltVerkefni.c._verkefni_a==self.verkefni,SkyltVerkefni.c._verkefni_b==self.verkefni) ) relations = [] for sv in related: if sv.verkefni_a == self: relations.append((sv.verkefni_b, sv.athugasemd))
[sqlalchemy] Re: Separate version table
Hi there, On 10/28/07, mmstud [EMAIL PROTECTED] wrote: Next design problem for me is version table. I have Document model with DocumentVersion model, but i dont know how to: - get the latest version of document - set creator and updator, automatic behavior for this - update version number - fetch thru Document(s) and DocumentVersion(s) I didn't read your code thoroughly, but I have a model with some similarities. Perhaps it will provide some insight. Basically, I'm dealing with Pages and PageVersions. PageVersions refers to it's parent Page, but Page also keeps the version number of the latest version. Arnar # encoding: utf-8 import os from datetime import datetime from sqlalchemy import * from softproof import utils from softproof.json import jsonify_saobject __meta__ = metadata def constructor(fun): def decorated(self, *args, **kw): assert hasattr(self, 'c') for key,value in kw.items(): if hasattr(self.c, key): setattr(self, key, value) del kw[key] fun(self, *args, **kw) return decorated jobs = Table(jobs, __meta__, Column(jobno, Unicode(15), primary_key=True), Column(created, DateTime, nullable=False, default=datetime.now), Column(deleted, Boolean, nullable=False, default=False)) class Job(object): @constructor def __init__(self, jobno=None): if jobno: self.jobno = jobno def sortedpages(self): listcopy = self.pages[:] listcopy.sort(key=Page.sort_key) return listcopy def get_page_by_name(self, pagename): Finnur síðu með nafnið pagename og skilar henni. Skilar None ef engin síða hefur viðkomandi nafn. Ef pagename er _firstpage_ er skilað viðeigandi síðu (t.d. kápu ef hún er til) if len(self.pages) == 0: return None if '_firstpage_' == pagename: for p in self.pages: if 'KAP' in p.pagename: return p return self.pages[0] for p in self.pages: if p.pagename == pagename: return p return None def create_page(self, pagename, *args, **kwargs): p = Page(job=self, pagename=pagename, *args, **kwargs) return p def get_path(self): if self.jobno.startswith('P'): pg1, pg2, pg3 = self.jobno.split('.') return os.path.join(pg1, pg1+'.'+pg2, self.jobno) else: return os.path.join(self.jobno[:-3]+'000', self.jobno[:-2]+'00', self.jobno) mapper(Job, jobs) pageversions = Table(pageversions, __meta__, Column(jobno, Unicode(15), ForeignKey(pages.jobno), primary_key=True), Column(pagename, Unicode(30), ForeignKey(pages.pagename), primary_key=True), Column(version, Integer, primary_key=True, default=1), Column(created, DateTime, nullable=False, default=datetime.now), Column(md5sum, String(32)), Column(width, Integer, nullable=False, default=0), Column(height, Integer, nullable=False, default=0), ForeignKeyConstraint([jobno, pagename],[pages.jobno, pages.pagename])) class PageVersion(object): @constructor def __init__(self, page=None, version=None): if page: self.page = page if version: self.version = version @property def filename(self): if self.version == 1: return self.page.pagename + '.jpg' else: return %s.v%02d.jpg % (self.page.pagename, self.version) mapper(PageVersion, pageversions) PageStates = utils.Enum('new', 'approved', 'rejected') pages = Table(pages, __meta__, Column(jobno, Unicode(15), ForeignKey(jobs.jobno), primary_key=True), Column(pagename, Unicode(30), primary_key=True), Column(created, DateTime, nullable=False, default=datetime.now), Column(deleted, Boolean, nullable=False, default=False), Column(current_version, Integer), Column(status, PageStates, nullable=False, default=PageStates.new)) class Page(object): @constructor def __init__(self, job=None, pagename=None): if job: self.job = job if pagename: self.pagename = pagename self.currentversion = PageVersion(self, 1) self.status = PageStates.new def add_version(self): self.currentversion = PageVersion(self, self.currentversion.version+1) self.status = PageStates.new comment = self.add_comment() comment.closeable = False comment.content = u'Ný útgáfa rippuð' return self.currentversion def get_version(self, versionno): return self.versions[versionno-1] def _get_status(self): return self._status def _set_status(self, newstatus): if self._status is
[sqlalchemy] Re: Separate version table
Next design problem for me is version table. I have Document model with DocumentVersion model, but i dont know how to: - get the latest version of document - set creator and updator, automatic behavior for this - update version number - fetch thru Document(s) and DocumentVersion(s) just to warn you, if u're trying to have a versioned document, i.e. document with history of changes/versions, and track them in time, that's a rather complicated thing. see bitemporal mixin recipe in dbcook: https://dbcook.svn.sourceforge.net/svnroot/dbcook/trunk/dbcook/misc/timed2/ if u don't realy care about the history, but only need the last one, that might be easier, YMMV. automatic setup of fields in an object, e.g. in your case creator/modifier of document, might be done at several places/times: - object's constructor - just before saving the object to DB - mapperEextension.befor_insert and friends - maybe other places to hook between these two but u'll need a context-like state to keep track of the current user (or time or whatever). or, u can do it by hand somewhere at proper place within your workflow, around saving the object. Beware that either way it must be done in a way that does not change/affect objects which have not been really modified - else all objects will be always saved/updated, over and over. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Separate version table
Thanks there were some good ideas to try. Btw. what does the first def constructor(fun)? On 28 loka, 18:00, Arnar Birgisson [EMAIL PROTECTED] wrote: Hi there, On 10/28/07, mmstud [EMAIL PROTECTED] wrote: Next design problem for me is version table. I have Document model with DocumentVersion model, but i dont know how to: - get the latest version of document - set creator and updator, automatic behavior for this - update version number - fetch thru Document(s) and DocumentVersion(s) I didn't read your code thoroughly, but I have a model with some similarities. Perhaps it will provide some insight. Basically, I'm dealing with Pages and PageVersions. PageVersions refers to it's parent Page, but Page also keeps the version number of the latest version. Arnar # encoding: utf-8 import os from datetime import datetime from sqlalchemy import * from softproof import utils from softproof.json import jsonify_saobject __meta__ = metadata def constructor(fun): def decorated(self, *args, **kw): assert hasattr(self, 'c') for key,value in kw.items(): if hasattr(self.c, key): setattr(self, key, value) del kw[key] fun(self, *args, **kw) return decorated jobs = Table(jobs, __meta__, Column(jobno, Unicode(15), primary_key=True), Column(created, DateTime, nullable=False, default=datetime.now), Column(deleted, Boolean, nullable=False, default=False)) class Job(object): @constructor def __init__(self, jobno=None): if jobno: self.jobno = jobno def sortedpages(self): listcopy = self.pages[:] listcopy.sort(key=Page.sort_key) return listcopy def get_page_by_name(self, pagename): Finnur síðu með nafnið pagename og skilar henni. Skilar None ef engin síða hefur viðkomandi nafn. Ef pagename er _firstpage_ er skilað viðeigandi síðu (t.d. kápu ef hún er til) if len(self.pages) == 0: return None if '_firstpage_' == pagename: for p in self.pages: if 'KAP' in p.pagename: return p return self.pages[0] for p in self.pages: if p.pagename == pagename: return p return None def create_page(self, pagename, *args, **kwargs): p = Page(job=self, pagename=pagename, *args, **kwargs) return p def get_path(self): if self.jobno.startswith('P'): pg1, pg2, pg3 = self.jobno.split('.') return os.path.join(pg1, pg1+'.'+pg2, self.jobno) else: return os.path.join(self.jobno[:-3]+'000', self.jobno[:-2]+'00', self.jobno) mapper(Job, jobs) pageversions = Table(pageversions, __meta__, Column(jobno, Unicode(15), ForeignKey(pages.jobno), primary_key=True), Column(pagename, Unicode(30), ForeignKey(pages.pagename), primary_key=True), Column(version, Integer, primary_key=True, default=1), Column(created, DateTime, nullable=False, default=datetime.now), Column(md5sum, String(32)), Column(width, Integer, nullable=False, default=0), Column(height, Integer, nullable=False, default=0), ForeignKeyConstraint([jobno, pagename],[pages.jobno, pages.pagename])) class PageVersion(object): @constructor def __init__(self, page=None, version=None): if page: self.page = page if version: self.version = version @property def filename(self): if self.version == 1: return self.page.pagename + '.jpg' else: return %s.v%02d.jpg % (self.page.pagename, self.version) mapper(PageVersion, pageversions) PageStates = utils.Enum('new', 'approved', 'rejected') pages = Table(pages, __meta__, Column(jobno, Unicode(15), ForeignKey(jobs.jobno), primary_key=True), Column(pagename, Unicode(30), primary_key=True), Column(created, DateTime, nullable=False, default=datetime.now), Column(deleted, Boolean, nullable=False, default=False), Column(current_version, Integer), Column(status, PageStates, nullable=False, default=PageStates.new)) class Page(object): @constructor def __init__(self, job=None, pagename=None): if job: self.job = job if pagename: self.pagename = pagename self.currentversion = PageVersion(self, 1) self.status = PageStates.new def add_version(self): self.currentversion = PageVersion(self, self.currentversion.version+1) self.status = PageStates.new comment = self.add_comment() comment.closeable = False
[sqlalchemy] Re: Separate version table
On 10/28/07, mmstud [EMAIL PROTECTED] wrote: Thanks there were some good ideas to try. Btw. what does the first def constructor(fun)? It is a decorator I use on mapped classes constructors. It allows me to give keyword arguments to constructors with initial values for any field in class.c (i.e. any mapped columns). cheers, Arnar --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---