SQLAlchemy sürüm sınıfı ithalat sipariş önemsiyor
Burada kılavuzu takip ediyordum:
http://www.sqlalchemy.org/docs/orm/examples.html?highlight=versioning#versioned-objects
ve bir sorun rastlamak var. Benim gibi tanımlanmış ilişkileri var:
generic_ticker = relation('MyClass', backref=backref("stuffs"))
model benim modülleri alma sırası hakkında hiçbir şey umurunda değil yani dizeler. Bu normalde gayet iyi çalışıyor ama sürüm meta kullandığımda aşağıdaki hatayı alıyorum:
sqlalchemy.TL İnvalidRequestError: başlatılıyor eşleyici, Eşleyici|Sınıfım|maddeleri, 'Tüccar' bir isim bulamadı ("'' tanımlı değil"). Sınıfım adını ifade Eğer bu sınıf bir adı varsa, bu ilişki eklemeyi düşünün() hem de bağımlı sınıfları belirlendikten sonra, sınıf için.
Aşağı hata buldum:
File "/home/nick/workspace/gm3/gm3/lib/history_meta.py", line 90, in __init__
mapper = class_mapper(cls)
File "/home/nick/venv/tg2env/lib/python2.6/site-packages/sqlalchemy/orm/util.py", line 622, in class_mapper
mapper = mapper.compile()
class VersionedMeta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
DeclarativeMeta.__init__(cls, classname, bases, dict_)
try:
mapper = class_mapper(cls)
_history_mapper(mapper)
except UnmappedClassError:
pass
Try koyarak sorunu hallettim: lambda ve tüm ithalat oldu sonra onlara çalışan şeyler dışında. Bu çalışıyor ama biraz saçma gibi görünüyor, bu iyi bir yoldur nasıl düzeltmek için herhangi bir fikir?
Teşekkürler!
Güncelleme
Sorun aslında alma sırası değil. Sürüm örnek eşleyici her sürüm bilgisi sınıf costructor derleme gerektirir şekilde tasarlanmıştır. Derleme ve ilgili sınıfları henüz tanımlanmamış başarısız. Dairesel ilişkilerin durumda eşlenen sınıflar tanımı sipariş değiştirerek çalışma yapmak için bir yol yoktur.
Güncelleme 2
Güncelleme durumları yukarıdaki (burada diğer insanların geçemeyeceğim:) bilmiyordum) bu döngüsel başvurular nedeniyle olasıdır. Benim yararlı hack bulacak biri olabilir (turbogears ile kullanıyorum) (VersionedMeta Değiştirin ve create_mappers history_meta küresel ekleyin)
create_mappers = []
class VersionedMeta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
DeclarativeMeta.__init__(cls, classname, bases, dict_)
#I added this code in as it was crashing otherwise
def make_mapper():
try:
mapper = class_mapper(cls)
_history_mapper(mapper)
except UnmappedClassError:
pass
create_mappers.append(lambda: make_mapper())
Daha sonra modeller aşağıdaki gibi bir şey __init__.py yapabilirsiniz
# Import your model modules here.
from myproj.lib.history_meta import create_mappers
from myproj.model.misc import *
from myproj.model.actor import *
from myproj.model.stuff1 import *
from myproj.model.instrument import *
from myproj.model.stuff import *
#setup the history
[func() for func in create_mappers]
Bu şekilde tüm sınıfları tanımlanmış sonra mappers oluşturun.
Güncelleme 3 Biraz alakasız ama yinelenen bazı durumlarda, birincil anahtar hata (tek seferde aynı nesneyi 2 değişiklik yapılıyor) rastladım. Benim geçici çözüm, yeni bir ilköğretim otomatik artan anahtar eklemek için olmuştur. Tabii ki de-birincil varolan şeyler geçmiş tablo oluşturmak için kullanılan anahtar vardı bu yüzden mysql ile 1'den fazla olamaz. Benim genel bir kod (bir hist_id ve yabancı anahtar kısıtlaması kurtulmak da dahil olmak üzere) kontrol edin:
"""Stolen from the offical sqlalchemy recpies
"""
from sqlalchemy.ext.declarative import DeclarativeMeta
from sqlalchemy.orm import mapper, class_mapper, attributes, object_mapper
from sqlalchemy.orm.exc import UnmappedClassError, UnmappedColumnError
from sqlalchemy import Table, Column, ForeignKeyConstraint, Integer
from sqlalchemy.orm.interfaces import SessionExtension
from sqlalchemy.orm.properties import RelationshipProperty
from sqlalchemy.types import DateTime
import datetime
from sqlalchemy.orm.session import Session
def col_references_table(col, table):
for fk in col.foreign_keys:
if fk.references(table):
return True
return False
def _history_mapper(local_mapper):
cls = local_mapper.class_
# set the "active_history" flag
# on on column-mapped attributes so that the old version
# of the info is always loaded (currently sets it on all attributes)
for prop in local_mapper.iterate_properties:
getattr(local_mapper.class_, prop.key).impl.active_history = True
super_mapper = local_mapper.inherits
super_history_mapper = getattr(cls, '__history_mapper__', None)
polymorphic_on = None
super_fks = []
if not super_mapper or local_mapper.local_table is not super_mapper.local_table:
cols = []
for column in local_mapper.local_table.c:
if column.name == 'version':
continue
col = column.copy()
col.unique = False
#don't auto increment stuff from the normal db
if col.autoincrement:
col.autoincrement = False
#sqllite falls over with auto incrementing keys if we have a composite key
if col.primary_key:
col.primary_key = False
if super_mapper and col_references_table(column, super_mapper.local_table):
super_fks.append((col.key, list(super_history_mapper.base_mapper.local_table.primary_key)[0]))
cols.append(col)
if column is local_mapper.polymorphic_on:
polymorphic_on = col
#if super_mapper:
# super_fks.append(('version', super_history_mapper.base_mapper.local_table.c.version))
cols.append(Column('hist_id', Integer, primary_key=True, autoincrement=True))
cols.append(Column('version', Integer))
cols.append(Column('changed', DateTime, default=datetime.datetime.now))
if super_fks:
cols.append(ForeignKeyConstraint(*zip(*super_fks)))
table = Table(local_mapper.local_table.name '_history', local_mapper.local_table.metadata,
*cols, mysql_engine='InnoDB')
else:
# single table inheritance. take any additional columns that may have
# been added and add them to the history table.
for column in local_mapper.local_table.c:
if column.key not in super_history_mapper.local_table.c:
col = column.copy()
super_history_mapper.local_table.append_column(col)
table = None
if super_history_mapper:
bases = (super_history_mapper.class_,)
else:
bases = local_mapper.base_mapper.class_.__bases__
versioned_cls = type.__new__(type, "%sHistory" % cls.__name__, bases, {})
m = mapper(
versioned_cls,
table,
inherits=super_history_mapper,
polymorphic_on=polymorphic_on,
polymorphic_identity=local_mapper.polymorphic_identity
)
cls.__history_mapper__ = m
if not super_history_mapper:
cls.version = Column('version', Integer, default=1, nullable=False)
create_mappers = []
class VersionedMeta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
DeclarativeMeta.__init__(cls, classname, bases, dict_)
#I added this code in as it was crashing otherwise
def make_mapper():
try:
mapper = class_mapper(cls)
_history_mapper(mapper)
except UnmappedClassError:
pass
create_mappers.append(lambda: make_mapper())
def versioned_objects(iter):
for obj in iter:
if hasattr(obj, '__history_mapper__'):
yield obj
def create_version(obj, session, deleted = False):
obj_mapper = object_mapper(obj)
history_mapper = obj.__history_mapper__
history_cls = history_mapper.class_
obj_state = attributes.instance_state(obj)
attr = {}
obj_changed = False
for om, hm in zip(obj_mapper.iterate_to_root(), history_mapper.iterate_to_root()):
if hm.single:
continue
for hist_col in hm.local_table.c:
if hist_col.key == 'version' or hist_col.key == 'changed' or hist_col.key == 'hist_id':
continue
obj_col = om.local_table.c[hist_col.key]
# get the value of the
# attribute based on the MapperProperty related to the
# mapped column. this will allow usage of MapperProperties
# that have a different keyname than that of the mapped column.
try:
prop = obj_mapper.get_property_by_column(obj_col)
except UnmappedColumnError:
# in the case of single table inheritance, there may be
# columns on the mapped table intended for the subclass only.
# the "unmapped" status of the subclass column on the
# base class is a feature of the declarative module as of sqla 0.5.2.
continue
# expired object attributes and also deferred cols might not be in the
# dict. force it to load no matter what by using getattr().
if prop.key not in obj_state.dict:
getattr(obj, prop.key)
a, u, d = attributes.get_history(obj, prop.key)
if d:
attr[hist_col.key] = d[0]
obj_changed = True
elif u:
attr[hist_col.key] = u[0]
else:
# if the attribute had no value.
attr[hist_col.key] = a[0]
obj_changed = True
if not obj_changed:
# not changed, but we have relationships. OK
# check those too
for prop in obj_mapper.iterate_properties:
if isinstance(prop, RelationshipProperty) and \
attributes.get_history(obj, prop.key).has_changes():
obj_changed = True
break
if not obj_changed and not deleted:
return
attr['version'] = obj.version
hist = history_cls()
for key, value in attr.iteritems():
setattr(hist, key, value)
obj.version = 1
session.add(hist)
class VersionedListener(SessionExtension):
def before_flush(self, session, flush_context, instances):
for obj in versioned_objects(session.dirty):
create_version(obj, session)
for obj in versioned_objects(session.deleted):
create_version(obj, session, deleted = True)
CEVAP
Sadece tarayıcı hack benim uygulamada özel FF4 destek olmak için biraz hayal kırıklığına uğradım söylemeliyim. Yukarıdaki javascript çözümü, değişken genişlikli yazı tiplerini hesaba katmıyor. İşte bu hesaplar için daha kapsamlı bir senaryo. Bu çözüm büyük bir sorun varsa öğesi metin içeren kod çalıştırıldığında gizli ise, o zaman kutusunun genişliğini bilinen değildir. Bu test üzerinde çalışmayı bıraktım bu yüzden benim için bir anlaşma kırıcı oldu. ama birilerine faydası olur diye buraya yazı düşünmüştüm. Tabii bu benim test ayrıntılı daha az olduğunu da test etmeyi unutmayın. Sadece FF4 için kod çalıştırmak ve diğer tüm tarayıcılar mevcut çözüm kullanmak için bir tarayıcı kontrol eklemek istedim.
Bu burada işe yaramaz için kullanılabilir olması gerekir: http://jsfiddle.net/kn9Qg/130/
HTML:
<div id="test">hello World</div>
CSS:
#test {
margin-top: 20px;
width: 68px;
overflow: hidden;
white-space: nowrap;
border: 1px solid green;
}
Javascript (jQuery kullanır)
function ellipsify($c){
// <div $c> content container (passed)
// <div $b> bounds
// <div $o> outer
// <span $i> inner
// </div>
// <span $d></span> dots
// </div>
// </div>
var $i = $('<span>' $c.html() '</span>');
var $d = $('<span>...</span>');
var $o = $('<div></div>');
var $b = $('<div></div>');
$b.css( {
'white-space' : "nowrap",
'display' : "block",
'overflow': "hidden"
}).attr('title', $c.html());
$o.css({
'overflow' : "hidden",
'width' : "100%",
'float' : "left"
});
$c.html('').append($b.append( $o.append($i)).append($d));
function getWidth($w){
return parseInt( $w.css('width').replace('px', '') );
}
if (getWidth($o) < getWidth($i))
{
while (getWidth($i) > (getWidth($b) - getWidth($d)) )
{
var content = $i.html();
$i.html(content.substr(0, content.length - 1));
}
$o.css('width', (getWidth($b) - getWidth($d)) 'px');
}
else
{
var content = $i.html();
$c.empty().html(content);
}
}
Gibi olur:
$(function(){
ellipsify($('#test'));
});
AZALAN TARAFINDAN SİPARİŞ SQLAlchemy?...
HTML amacı "no-js" sınıfı ne...
Sürüm kontrolü içine NuGet paketleri k...
NuGet ve dağıtılmış sürüm kontrol (DVC...
Raylar üzerinde Ruby, String sınıfı ge...