Круговой импорт в зефир

У меня есть два объекта, которые связаны друг с другом. Я хотел бы иметь доступ к одному объекту через другой, пройдя через связанный атрибут.

E.g. A.b_relationship.obj.some_property

Как я могу сделать это, не создавая циклический импорт?

# lib.py
class Relationship(object):

    def __init__(self, obj):
        self.obj = obj


# a.py
class A(object):
    b_relationship = Relationship(B)

# b.py
class B(object):
    a_relationship = Relationship(A)

Для ясности я добавил этот дополнительный пример. Очевидно, что SQLAlchemy решила эту проблему с помощью атрибута backref. Я не уверен, насколько осуществимо для меня внедрить подобные вещи в зефир, не нарушая того, как это работает. Может быть, мне нужно изменить свое мышление?

from marshmallow import Schema
from marshmallow.fields import String

from project.database import db


class PersonModel(db.Model):
    name = db.Column(db.String)


class PetModel(db.Model):
    name = db.Column(db.String)
    owner = db.relationship('PersonModel', backref='pets')


class PersonSchema(Schema):
    name = fields.String(init_arg='some value')
    pets = fields.Relationship(related_schema=PetSchema)


class PetSchema(Schema):
    name = fields.String()
    owner = fields.Relationship(related_schema=PersonSchema)

person Colton Allen    schedule 25.01.2016    source источник
comment
Создайте __init__ и импортируйте туда A и B. Затем вы можете избежать циклического импорта в a.py и b.py. Это может быть актуально   -  person inspectorG4dget    schedule 26.01.2016
comment
Вы говорите, что у вас есть два объекта, связанных друг с другом, но вы устанавливаете отношения на уровне класса. Хотя классы действительно являются объектами, это не похоже на полезную ссылку для создания. Вы хотите, чтобы экземпляр A был связан с экземпляром B и наоборот, или вы хотите, чтобы классы были связаны? Ссылка на уровне класса довольно бесполезна. Кроме того, как создаются экземпляры этих классов? Возникают ли они вместе или создаются независимо?   -  person user2357112 supports Monica    schedule 26.01.2016
comment
@ user2357112 Сами классы не должны быть связаны друг с другом. Они не заботятся друг о друге. Это атрибуты _relationship, которые необходимо связать. Позже я отключу эти поля и использую связанный объект для выполнения некоторых расчетов.   -  person Colton Allen    schedule 26.01.2016
comment
@user2357112 user2357112 По сути, я хочу иметь возможность выполнить A.rel, чтобы получить B, и B.rel, чтобы получить A.   -  person Colton Allen    schedule 26.01.2016
comment
тогда вам нужно сделать атрибут relationship атрибутом instance, а не атрибутом class, как сейчас. Кстати, уберите префикс (a_ и b_)   -  person Pynchia    schedule 26.01.2016
comment
хм... Я ответил на ваш ответ выше, но теперь ваш последний комментарий еще больше сбивает с толку. Вы хотите связать classes или objects?   -  person Pynchia    schedule 26.01.2016
comment
Что класс Relationship должен делать на практике? У меня ощущение, что это не нужно. Чего вы пытаетесь достичь?   -  person François Constant    schedule 26.01.2016
comment
@François Все, что я хочу сделать, это включить некоторую конфигурацию, чтобы я мог просматривать атрибуты одного объекта на другом. Итак, если я работаю с экземпляром B и хочу узнать значение некоторого поля в объекте A. Я могу добраться до A, используя специальный атрибут B.   -  person Colton Allen    schedule 26.01.2016
comment
@Pynchia Я использую marshmallow. Вы определяете поля в объекте схемы. Эти поля сами являются объектами. Некоторые объекты представляют отношения в базе данных. Поскольку модели sqlalchemy связаны, я бы хотел, чтобы схемы были связаны аналогичным образом, чтобы я мог выполнить некоторую полезную проверку перекрестной схемы.   -  person Colton Allen    schedule 26.01.2016
comment
@ColtonAllen, не могли бы вы привести конкретный пример того, какими могут быть A и B? и собственности?   -  person François Constant    schedule 26.01.2016
comment
@ Франсуа Франсуа, я добавил пример. A и B являются объектами схемы.   -  person Colton Allen    schedule 26.01.2016
comment
Ах, это для ORM! Никогда не слышал о marshmallow, но все равно ответил :)   -  person François Constant    schedule 26.01.2016


Ответы (2)


Отсюда: http://marshmallow.readthedocs.org/en/latest/nesting.html#two-way-nesting

Посмотрите, как строка используется для класса; AuthorSchema относится к BookSchema:

class AuthorSchema(Schema):
    # Make sure to use the 'only' or 'exclude' params
    # to avoid infinite recursion
    books = fields.Nested('BookSchema', many=True, exclude=('author', ))
    class Meta:
        fields = ('id', 'name', 'books')

class BookSchema(Schema):
    author = fields.Nested(AuthorSchema, only=('id', 'name'))
    class Meta:
        fields = ('id', 'title', 'author')

Я предполагаю, что в вашем случае вы хотите сделать то же самое с many=False. Я никогда не использовал зефир, но в Django это похоже, мы используем путь к классу, например «my_app.MyClass», вместо MyClass, чтобы избежать циклического импорта.

person François Constant    schedule 25.01.2016
comment
Спасибо, приятель! Я не знал, что у зефира уже есть эта функция. Вот что я получаю за предположение. - person Colton Allen; 26.01.2016

Вы можете реализовать RelationshipManager (также известный как реестр), в котором должны быть зарегистрированы все классы, которые могут быть частью отношения.

Инициализатор Relationship может взять имя класса, с которым он связан, а не фактический объект класса.

Наконец, сам класс отношений может лениво загружать реальный класс, с которым он связан, из имени, заданного при инициализации (через диспетчер).

person Tom Dalton    schedule 25.01.2016