Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 15, 2015 20:57:15

lightarhont
Зарегистрирован: 2014-07-20
Сообщения: 44
Репутация: +  1  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

Помогите ибо не нагуглить…

Хочется сделать так, что-бы существовала общая некая табличная схема. Которую расширяют классы с функциями, которые и являются в конечном счёте моделями.

Вероятно это выглядит так:

Схемы:

from sqlalchemy import (Column, Integer, Unicode, Text, ForeignKey)
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import (relationship, backref)
class IDB:
    __table_args__ = {'mysql_engine':'InnoDB', 'mysql_collate': 'utf8_general_ci', 'extend_existing': True}
class PKID:
    id = Column(Integer, primary_key=True)
class SUsers(IDB, PKID):
    
    __tablename__ = 'users'
    
    username = Column(Unicode(32), unique=True)
    email    = Column(Unicode(32), unique=True)
    password = Column(Unicode(64))
    created = Column(Integer)
    activity = Column(Integer)
    
    @declared_attr
    def roles(cls):
        return association_proxy('roles_users', 'roles')
    
    @declared_attr
    def profiles(cls):
        return relationship("Profiles", uselist=False)
class SProfiles(IDB, PKID):
    
    __tablename__ = 'profiles'
    
    @declared_attr
    def userid(cls):
        return Column(Integer, ForeignKey('users.id'))
    
    fullname  = Column(Unicode(64))
    avatar1   = Column(Unicode(32))
    avatar2   = Column(Unicode(32))
    avatar3   = Column(Unicode(32))
class SRoles(IDB, PKID):
    
    __tablename__ = 'roles'
    
    name        = Column(Unicode(16))
    rolesgroup  = Column(Unicode(16))
    description = Column(Unicode(255))
    ordering    = Column(Integer)
    
    @declared_attr
    def permissions(cls):
        return association_proxy('perms_roles', 'permissions')
    
    @declared_attr
    def users(cls):
        return association_proxy('roles_users', 'users')

import time
import datetime
from testproject.models import Base
from testproject.models.shemas import (SUsers, SProfiles, SRoles, SPermissions, SBlocks, SRolesUsers, SPermissionsRoles)
class Users(SUsers, Base):
    
    def __init__(self, username, email, password, created, activity=None, profiles=None, roles=None):
        self.username = username
        self.email    = email
        self.password = password
        self.created = created
        if activity:
            self.activity = activity
        if profiles:
            self.profiles = profiles
        if roles:
            self.roles  = roles
        
    def check_password(self, passwd):
        return self.password == passwd
    
    def datefromtimestamp(self, dateformat='%Y-%m-%d %H:%M:%S'):
        return str(datetime.datetime.fromtimestamp(self.created).strftime(dateformat))
    
    def activityparams(self, activitytime=300, classactiv='useract', classnoactiv='usernoact', dateformat='%Y-%m-%d %H:%M:%S'):
        if (int(time.time()) - self.activity) <= activitytime:
            p1 = classactiv
        else:
            p1 = classnoactiv
        p2 = str(datetime.datetime.fromtimestamp(self.activity).strftime(dateformat))
        return (p1, p2)
class Profiles(SProfiles, Base):
    
    def __init__(self, fullname, register=None, lastlogin=None, expired=None, avatar1=None, avatar2=None, avatar3=None):
        self.fullname  = fullname
        if avatar1:
            self.avatar1   = avatar1
        if avatar2:
            self.avatar2   = avatar2
        if avatar3:
            self.avatar3   = avatar3
class Roles(SRoles, Base):
    
    def __init__(self, name, rolesgroup, description=None, ordering=None):
        self.name = name
        self.rolesgroup = rolesgroup
        if description:
            self.description = description
        if ordering:
            self.ordering = ordering
    
    def shortdesc(self, getsize=68):
        if len(self.description) >= getsize:
            return self.description[:getsize] + '...'
        else:
            return self.description
class Permissions(SPermissions, Base):
    
    def __init__(self, permname, description=None, ordering=None):
        self.permname = permname
        if description:
            self.description = description
        if ordering:
            self.ordering = ordering
    
    def shortdesc(self, getsize=68):
        if len(self.description) >= getsize:
            return self.description[:getsize] + '...'
        else:
            return self.description

Предполагается, что для группу таких моделей хранить в каком то пакете. Например у меня это в пакете rbac. Внутри ещё несколько модулей, для функций:

from sqlalchemy import (desc, asc)
from testproject.models import DBSession
from . import Users, Roles 
def get_user2(itemid):
    return DBSession.query(Users).filter(Users.id == itemid).one()
def get_user(username):
    user = DBSession.query(Users).filter(Users.username == username).all()
    if user:
        return user[0]
    else:
        return None
def add_user():
    pass
#Удалить пользователей по списку
def delete_users(delitems):
    try:
        for e in delitems:
            DBSession.query(Users).filter(Users.id == e).delete()
        transaction.commit()
        result = 1
    except:
        transaction.rollback()
        result = 0
    return result
def get_users(offset=None, limit=None):
    if offset==None or limit==None:
        return DBSession.query(Users).all()
    else:
        return (DBSession.query(Users).all())[offset:limit]

Всё бы хорошо, но мне нужно делать такую схему в каждом __init__.py Где я хочу писать свои функции для моделей.
Тогда возникает проблема, что называть их Users, Roles, Profiles уже не получается - Возникает ошибка.
В то время как и изменять имена классов например: Public_Comments_Users не получается - Возникают проблемы со связями между таблицами в схеме данных.

Как тут быть?

Офлайн

#2 Апрель 15, 2015 21:42:30

bismigalis
Зарегистрирован: 2010-10-02
Сообщения: 449
Репутация: +  47  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

не понял в чем трудность

там где надо делать запросы импортируешь модели



Офлайн

#3 Апрель 15, 2015 21:55:42

lightarhont
Зарегистрирован: 2014-07-20
Сообщения: 44
Репутация: +  1  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

bismigalis
не понял в чем трудностьтам где надо делать запросы импортируешь модели
Вот он и хрюкает, потому что при изменении названия моделей - Он не может найти связанные модели по схеме.

Вот например:
class SBlocks(IDB, PKID):
    
    __tablename__ = 'blocks'
    
    @declared_attr
    def user_id(cls):
        return Column(Integer, ForeignKey('users.id'))
    
    @declared_attr
    def permission_id(cls):
        return Column(Integer, ForeignKey('permissions.id'))
    
    @declared_attr
    def fromuser_id(cls):
        return Column(Integer, ForeignKey('users.id'))
    
    datestart = Column(Integer)
    dateend = Column(Integer)
    blockcomment = Column(Unicode(255))
    
    @declared_attr
    def users(cls):
        return relationship("Users", uselist=False, primaryjoin="Users.id == Blocks.user_id")
    
    @declared_attr
    def permissions(cls):
        return relationship("Permissions", uselist=False)
    
    @declared_attr
    def fusers(cls):
        return relationship("Users", uselist=False, primaryjoin="Users.id == Blocks.fromuser_id")

При расширении этого класса Через например class Public_Comments_Blocks(SBlocs, Base) свзяи в схеме начинают рушится:

@declared_attr
def users(cls):
return relationship(“Users”, uselist=False, primaryjoin="Users.id == Blocks.user_id“)

Как в этом случае быть я не совсем понимаю. Вводить какую-то переменную в схему, что-бы у нас теблица была не Users, а Public_Comments_Users

т.е. что-бы было как-то так:

@declared_attr
def users(cls):
return relationship(”Users“, uselist=False, primaryjoin=”Public_Comments_Users.id == Blocks.user_id")

Офлайн

#4 Апрель 15, 2015 21:57:16

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

bismigalis
Я понял в чем проблема. Он захардкорил в схемах во всех связях названия связанных классов. Поэтому при наследовании, если класс, который наследует имеет другое имя, то автоматом накрывается медным тазом связь с другим классом, который тоже, естественно поменяет __name__.

Если я правильно понял проблему, то вижу тут 2 пути:
1. Называть все с одним префиксом и в @declared_attr формировать связь учитывая базовый префикс.
2. Сделать связь на уровне таблиц и не переопределять параметр __table__, а оставить его как в базовом классе.

Офлайн

#5 Апрель 15, 2015 21:57:56

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

Правильно я все же понял

Офлайн

#6 Апрель 15, 2015 22:03:19

lightarhont
Зарегистрирован: 2014-07-20
Сообщения: 44
Репутация: +  1  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

А ещё исключение пишет, что проблему можно решить не меняя имя класса, т.е. оставив Users, а указав полный путь. Но как это сделать я не понял…

Офлайн

#7 Апрель 15, 2015 22:06:15

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

lightarhont
А ещё исключение пишет, что проблему можно решить не меняя имя класса, т.е. оставив Users, а указав полный путь. Но как это сделать я не понял…

Вот если бы его увидеть

Офлайн

#8 Апрель 15, 2015 22:11:17

lightarhont
Зарегистрирован: 2014-07-20
Сообщения: 44
Репутация: +  1  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

4kpt_III
Вот если бы его увидеть
Ну у админки rbac будет
testproject.models.manager.rbac import Users
У комментариев
testproject.models.public.comments import Users

Или я что-то не понял?

Офлайн

#9 Апрель 15, 2015 22:13:29

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

Исключение, сер, исключение

Офлайн

#10 Апрель 15, 2015 22:17:48

lightarhont
Зарегистрирован: 2014-07-20
Сообщения: 44
Репутация: +  1  -
Профиль   Отправить e-mail  

sqlalchemy проблема с примесями

4kpt_III
Исключение, сер, исключение

Вот что в логе
2015-04-15 20:17:56,585 ERROR Exception at http://testproject.python/manager/options/control/users
traceback url: http://testproject.python/_debug_toolbar/exception?token=62275c783134555c786236365c783138235c7864635c7865665c7865305c78666527&tb=140692605120016
Traceback (most recent call last):
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid_debugtoolbar-2.0.2-py3.3.egg/pyramid_debugtoolbar/toolbar.py”, line 172, in toolbar_tween
response = _handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid_debugtoolbar-2.0.2-py3.3.egg/pyramid_debugtoolbar/panels/performance.py”, line 55, in resource_timer_handler
result = handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/tweens.py”, line 21, in excview_tween
response = handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/router.py”, line 163, in handle_request
response = view_callable(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 596, in __call__
return view(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 329, in attr_view
return view(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 305, in predicate_wrapper
return view(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 355, in rendered_view
result = view(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 472, in _class_requestonly_view
inst = view(request)
File “/mnt/webserver/pythonproject/testproject/testproject/views/manager/users.py”, line 139, in __init__
Manager.__init__(self, request, 0)
File “/mnt/webserver/pythonproject/testproject/testproject/views/manager/common.py”, line 59, in __init__
user = get_user2(request.authenticated_userid)
File “/mnt/webserver/pythonproject/testproject/testproject/models/manager/rbac/users_func.py”, line 7, in get_user2
return DBSession.query(Users).filter(Users.id == itemid).one()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/scoping.py”, line 150, in do
return getattr(self.registry(), name)(*args, **kwargs)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/session.py”, line 1165, in query
return self._query_cls(entities, self, **kwargs)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 108, in __init__
self._set_entities(entities)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 118, in _set_entities
self._set_entity_selectables(self._entities)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 151, in _set_entity_selectables
ent.setup_entity(*d)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 3036, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/util/langhelpers.py”, line 725, in __get__
obj.__dict__ = result = self.fget(obj)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 1877, in _with_polymorphic_mappers
configure_mappers()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 2589, in configure_mappers
mapper._post_configure_properties()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 1694, in _post_configure_properties
prop.init()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/interfaces.py”, line 144, in init
self.do_init()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 1549, in do_init
self._process_dependent_arguments()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 1573, in _process_dependent_arguments
setattr(self, attr, attr_value())
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/ext/declarative/clsregistry.py”, line 271, in __call__
x = eval(self.arg, globals(), self._dict)
File “<string>”, line 1, in <module>
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/util/_collections.py”, line 680, in __missing__
self = val = self.creator(key)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/ext/declarative/clsregistry.py”, line 252, in _access_cls
return _determine_container(key, cls._decl_class_registry)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/ext/declarative/clsregistry.py”, line 236, in _determine_container
value = value.attempt_get(, key)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/ext/declarative/clsregistry.py”, line 89, in attempt_get
(“.”.join(path + ))
sqlalchemy.exc.InvalidRequestError: Multiple classes found for path “Users” in the registry of this declarative base. Please use a fully module-qualified path.

А вот это когда не может найти пути:
2015-04-15 13:43:20,820 ERROR Exception at http://testproject.python/
traceback url: http://testproject.python/_debug_toolbar/exception?token=62275c7866325c7864645c7831365c786266485c7865653d7e2f5c78626627&tb=139851508717264
Traceback (most recent call last):
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid_debugtoolbar-2.0.2-py3.3.egg/pyramid_debugtoolbar/toolbar.py”, line 172, in toolbar_tween
response = _handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid_debugtoolbar-2.0.2-py3.3.egg/pyramid_debugtoolbar/panels/performance.py”, line 55, in resource_timer_handler
result = handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/tweens.py”, line 21, in excview_tween
response = handler(request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/router.py”, line 163, in handle_request
response = view_callable(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 355, in rendered_view
result = view(context, request)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/pyramid/config/views.py”, line 472, in _class_requestonly_view
inst = view(request)
File “/mnt/webserver/pythonproject/testproject/testproject/views/public/index.py”, line 17, in __init__
Public.__init__(self, request, 0)
File “/mnt/webserver/pythonproject/testproject/testproject/views/public/common.py”, line 38, in __init__
user = get_user2(request.authenticated_userid)
File “/mnt/webserver/pythonproject/testproject/testproject/models/public/common_func.py”, line 6, in get_user2
return DBSession.query(Public_Common_Users).filter(Public_Common_Users.id == itemid).one()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/scoping.py”, line 150, in do
return getattr(self.registry(), name)(*args, **kwargs)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/session.py”, line 1165, in query
return self._query_cls(entities, self, **kwargs)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 108, in __init__
self._set_entities(entities)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 118, in _set_entities
self._set_entity_selectables(self._entities)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 151, in _set_entity_selectables
ent.setup_entity(*d)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/query.py”, line 3036, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/util/langhelpers.py”, line 725, in __get__
obj.__dict__ = result = self.fget(obj)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 1877, in _with_polymorphic_mappers
configure_mappers()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 2589, in configure_mappers
mapper._post_configure_properties()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/mapper.py”, line 1694, in _post_configure_properties
prop.init()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/interfaces.py”, line 144, in init
self.do_init()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 1550, in do_init
self._setup_join_conditions()
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 1624, in _setup_join_conditions
can_be_synced_fn=self._columns_are_mapped
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 1897, in __init__
self._check_foreign_cols(self.primaryjoin, True)
File “/home/mikhail/.virtualenvs/testproject/lib/python3.3/site-packages/sqlalchemy/orm/relationships.py”, line 2414, in _check_foreign_cols
raise sa_exc.ArgumentError(err)
sqlalchemy.exc.ArgumentError: Could not locate any relevant foreign key columns for primary join condition ‘users.id = blocks.user_id’ on relationship Blocks.users. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version