Использование Factory Boy для определения трех взаимосвязанных моделей с Flask и SQLAlchemy - PullRequest
1 голос
/ 02 мая 2019

Я пытаюсь создать фабрики FactoryBoy для трех моделей со сложными отношениями на сайте Flask / SQLAlchemy. Модели:

from sqlalchemy.orm import backref
from ..shared import db


class User(db.Model):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)


class OAuth(db.Model):
    __tablename__ = "flask_dance_oauth"

    user_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False)
    provider_user_id = db.Column(db.String(40), nullable=False)

    user = db.relationship(
        User,
        lazy="Joined",
        uselist=False,
        backref=backref("oauth", uselist=True, lazy="select"),
    )


class TwitterUserData(db.Model):
    "Stores data about the User's twitter account."
    __tablename__ = "twitter_user_data"

    id = db.Column(db.Integer, primary_key=True)
    id_str = db.Column(db.String(191), nullable=False, unique=True)

    user = db.relationship(
        "User",
        secondary="flask_dance_oauth",
        primaryjoin="and_("
            "OAuth.provider_user_id == TwitterUserData.id_str, "
            "OAuth.provider == 'twitter'"
        ")",
        secondaryjoin="User.id == OAuth.user_id",
        uselist=False,
        lazy="select",
        viewonly=True,
        backref=backref("twitter_data", uselist=False, lazy="select"),
    )

Чтобы подвести итог отношений:

  • User.oauth является OAuth объектом
  • User.id отображается на OAuth.user_id
  • User.twitter_data является TwitterUserData объектом
  • TwitterUserData.user является User объектом
  • TwitterUserData.id_str отображается на OAuth.provider_user_id

Мои фабрики в настоящее время:

import factory


class OAuthFactory(factory.alchemy.SQLAlchemyModelFactory):
    class Meta:
        model = OAuth
        sqlalchemy_session = db.session
        sqlalchemy_session_persistence = "commit"


class TwitterUserDataFactory(factory.alchemy.SQLAlchemyModelFactory):
    class Meta:
        model = TwitterUserData
        sqlalchemy_session = db.session
        sqlalchemy_session_persistence = "commit"

    id_str = factory.Sequence(lambda n: (n * 1000000000000000))


class UserFactory(factory.alchemy.SQLAlchemyModelFactory):
    class Meta:
        model = User
        sqlalchemy_session = db.session
        sqlalchemy_session_persistence = "commit"

    twitter_data = factory.SubFactory(TwitterUserDataFactory)

    oauth = factory.SubFactory(
        OAuthFactory,
        user_id=factory.SelfAttribute("..id"),
        provider_user_id=factory.SelfAttribute("..twitter_data.id_str"),
    )

Используя это, oauth.user_id не может быть установлено, потому что «параметр 'id' неизвестен."

Вместо этого я попытался определить oauth в надежде, что в post_generation пользователь получит id:

    @factory.post_generation
    def oauth(obj, create, extracted, **kwargs):
        if not create:
            return
        oauth = oauth_factory(
            user_id=obj.id,
            provider_user_id=obj.twitter_data.id_str
        )
        return oauth 

Но здесь obj.twitter_data - это 'NoneType' object, что меня озадачивает.

Я не уверен, что еще попробовать.

...