[sqlalchemy] Re: Separate version table

2007-10-30 Thread mmstud

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

2007-10-29 Thread mmstud

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

2007-10-29 Thread sdobrev

 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

2007-10-29 Thread mmstud

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

2007-10-29 Thread Arnar Birgisson

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

2007-10-29 Thread mmstud

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

2007-10-29 Thread Arnar Birgisson

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

2007-10-28 Thread Arnar Birgisson

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

2007-10-28 Thread sdobrev

 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

2007-10-28 Thread mmstud

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

2007-10-28 Thread Arnar Birgisson

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
-~--~~~~--~~--~--~---