【问题标题】:SQLAlchemy Inconsistent Results Self Referential RelationshipsSQLAlchemy 不一致的结果自引用关系
【发布时间】:2021-01-31 04:29:49
【问题描述】:

所以我使用 FlaskSQLAlchemy 编写了一个推荐系统,当我测试它时,它有时有效,有时无效,我发现它非常混乱,任何帮助将不胜感激。

这是模型:

class User(TimestampMixin, UserMixin, db.Model):
    # __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
    public_id = db.Column(db.String(MaxLengths.public_id))
    email = db.Column(db.String(MaxLengths.email), unique=True, nullable=False)
    password = db.Column(db.String(MaxLengths.password))
    reset_password_code = db.Column(db.String(MaxLengths.reset_password_code))
    attempt_reset_password = db.Column(db.Boolean(), default=False)
    is_email_verified = db.Column(db.Boolean(), default=False)
    is_age_verified = db.Column(db.Boolean(), default=False)
    is_newsletter_registered = db.Column(db.Boolean(), default=True)
    balance = db.Column(db.Float(), default=0.0)
    lifetime_balance = db.Column(db.Float(), default=0.0)
    reviews = db.relationship('Review', backref='user')
    ref_code = db.Column(db.String(MaxLengths.ref_code))

    # NOTE: Ref relationships here

    referred_by_user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    referred_by_user = db.relationship(
        'User', foreign_keys=[referred_by_user_id], uselist=False
        )
    referred_to_user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    referred_to_users = db.relationship(
        'User', foreign_keys=[referred_to_user_id], post_update=True)

    discount_code_used_by_id = db.Column(
        db.Integer, db.ForeignKey('discount_code.id'))
    profile_pic = db.Column(db.Boolean(), default=False)
    id_verification_pics = db.Column(db.JSON(), default=[])

    orders = db.relationship('Orders', backref='user')

    login_attempts = db.relationship('LoginAttempt', backref='user')
    last_seen = db.Column(ArrowType, default=arrow.utcnow())
    # TODO: Update this upon placing an order
    total_spent = db.Column(db.Float(), default=0.0)
    billing_address_id = db.Column(db.Integer, db.ForeignKey('address.id'))
    shipping_address_id = db.Column(db.Integer, db.ForeignKey('address.id'))
    billing_address = db.relationship(
        'Address', foreign_keys=[billing_address_id], uselist=False)
    shipping_address = db.relationship(
        'Address', foreign_keys=[shipping_address_id], uselist=False)
    review_votes = db.relationship('ReviewVote', backref='user')
    consumer_id = db.Column(db.String(MaxLengths.consumer_id))

class Orders(TimestampMixin, db.Model):
    '''
    Orders database model and custom order related functions
    '''

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    status = db.Column(db.String(MaxLengths.order_status),
                       default="Order Pending")
    dest_address_id = db.Column(db.Integer, db.ForeignKey('address.id'))
    from_address_id = db.Column(db.Integer, db.ForeignKey('address.id'))
    dest_address = db.relationship('Address', foreign_keys=[
                                   dest_address_id], uselist=False)
    from_address = db.relationship('Address', foreign_keys=[
                                   from_address_id], uselist=False)
    products = db.relationship('Product', backref='orders')
    subtotal = db.Column(db.Float())
    shipping_fee = db.Column(db.Float(), nullable=False)
    tax_cost = db.Column(db.Float())
    tax_percent = db.Column(db.Float(), nullable=False)
    total = db.Column(db.Float())
    discount_code = db.relationship(
        'DiscountCode', uselist=False)
    discount_code_amount = db.Column(db.Float)
    user_balance_applied = db.Column(db.Float)
    currency = db.Column(db.String(MaxLengths.currency), default="CAD")
    date = db.Column(ArrowType, default=arrow.utcnow()
                     )  # datetime.datetime.now()
    # TODO: This should exist in the interac_payment obj/json
    is_payment_recieved = db.Column(
        db.Boolean(), nullable=False, default=False)
    interac_payment = db.Column(db.JSON(), default={})
    order_number = db.Column(db.String(MaxLengths.order_number), default='')
    tracking_number = db.Column(db.String(MaxLengths.tracking_number))
    tracking_info = db.Column(db.JSON)
    ref_record = db.relationship(
        'ReferralRecord', backref='order', uselist=False)

    def apply_ref_bonus(self, rate=1.5):
        if self.is_payment_recieved:
            # user = self.get_user()
            if not self.user:
                print("No user found for this order")
            if not self.user.referred_by_user:
                print('This user wasn\'t referred by anyone')
                print(self.user.referred_by_user)
            if self.user and self.user.referred_by_user:
                cashback = (self.subtotal * (rate / 100))
                record = ReferralRecord(
                    referred_by_user_email=self.user.referred_by_user.email,
                    referred_to_user_email=self.user.email,
                    cashback_amount=cashback)
                self.user.referred_by_user.balance += cashback
                self.user.referred_by_user.lifetime_balance += cashback
                self.ref_record = record
                db.session.add(record)
                db.session.add(self.user.referred_by_user)
                db.session.add(self.user)
                db.session.commit()


class DiscountCode(TimestampMixin, db.Model):
    '''
    :param id: int primary_key
    :param code: str discount code
    :param amount: float numeric representation of discount
    :param is_percent_off: bool amount is treated as a % discount if True
    :param minimum_subtotal: float minimum order subtotal for discount code to be valid for a given order
    :param expiration_date: datetime() the date a code is no longer valid
    :param uses: int the number of times the code has been used
    :param max_uses: int max number of times a code can be used before becoming invalid
    :param used_by: a list of User objects who have used this code (for analytical purposes)
    '''
    id = db.Column(db.Integer(), primary_key=True)
    code = db.Column(db.String(MaxLengths.discount_code),
                     unique=True, nullable=False)
    amount = db.Column(db.Float(), nullable=False)
    is_percent_off = db.Column(db.Boolean(), default=False)
    minimum_subtotal = db.Column(db.Float(), default=0.0)
    # TODO: add default via arrow.shift()
    start_date = db.Column(ArrowType)
    expiration_date = db.Column(ArrowType)
    uses = db.Column(db.Integer(), default=0)
    max_uses = db.Column(db.Integer(), default=0)
    order_id = db.Column(db.Integer, db.ForeignKey('orders.id'))

这是测试用例:

def referr(ref_by_user, ref_to_user):
    ref_by_user.referred_to_users.append(ref_to_user)
    ref_to_user.referred_by_user = ref_by_user
    db.session.add(ref_by_user)
    db.session.add(ref_to_user)
    db.session.commit()

@app.cli.command('test-ref')
def testref():
    db.drop_all()
    db.create_all()
    user1 = User(email='test1@example.com')
    user2 = User(email='test2@example.com')
    user3 = User(email='test3@example.com')
    order = Orders(shipping_fee=4.00, tax_percent=0.5, subtotal=15.00, total=18.50, is_payment_recieved=True, interac_payment={})
    db.session.add(user1)
    db.session.add(user2)
    db.session.add(user3)
    db.session.add(order)
    db.session.commit()
    # user1.referr(user2)
    # user1.referr(user3)
    # referr(user1, user2)
    # referr(user1, user3)
    user1.referred_to_users.append(user2)
    user1.referred_to_users.append(user3)
    user2.referred_by_user = user1
    user3.referred_by_user = user1
    print("This should be == 0 - ", user1.balance)
    user2.orders.append(order)
    # order.user = user2
    db.session.add(user1)
    db.session.add(user2)
    db.session.add(user3)
    db.session.add(order)
    db.session.commit()
    # user2.apply_ref_bonus_from_order(order)
    order.apply_ref_bonus()
    db.session.commit()
    print("This should be > 0 - ", user1.balance)
    print(user1.referred_to_users)

但有时我会得到以下输出:

This should be == 0 -  0.0
This should be > 0 -  0.22499999999999998
[<User 'test2@example.com'>, <User 'test3@example.com'>]

其他时候我得到这个输出:

This should be == 0 -  0.0
This user wasn't referred by anyone
None
This should be > 0 -  0.0
[<User 'test2@example.com'>, <User 'test3@example.com'>]

我使用相同的代码得到不同的输出,尽管每当我尝试使用来自 User 模型或作为独立函数的 referr() 包装器时,我总是得到后者的输出。当我不通过函数推荐用户时,会出现不一致的输出,老实说,我真的对整个事情感到困惑

【问题讨论】:

    标签: python flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我没有指定 remote_side 参数

    
        # NOTE: Ref relationships here
    
        referred_by_user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        referred_by_user = db.relationship(
            'User', foreign_keys=[referred_by_user_id], uselist=False,
            remote_side=[id] # This Solved the Issue
            )
        referred_to_user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        referred_to_users = db.relationship(
            'User', foreign_keys=[referred_to_user_id], post_update=True)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多