【问题标题】:Flask SQLAlchemy - session.add violates primary key constraintFlask SQLAlchemy - session.add 违反主键约束
【发布时间】:2021-04-14 17:42:40
【问题描述】:

我有一些带有整数主键的模型应该自动递增

class Enrolment(db.Model):
    __tablename__ = 'enrolment'
    id = db.Column(db.Integer, primary_key=True)
    class_id = db.Column(db.Integer, db.ForeignKey('class.id', ondelete='CASCADE'), nullable=False)
    student_id = db.Column(db.Integer, db.ForeignKey('student.id'), nullable=False)
    enrolment_date = db.Column(db.Date, default=date.today)
    status = db.Column(db.Boolean, default=True)

    payments = db.relationship("Payment", backref="enrolment", passive_deletes=True)
    attendance = db.relationship("Attendance", backref="enrolment", passive_deletes=True)

    __table_args__ = (
        db.UniqueConstraint('class_id', 'student_id'),
    )

class Attendance(db.Model):
    __tablename__ = 'attendance'
    id = db.Column(db.Integer, primary_key=True)
    enrolment_id = db.Column(db.Integer, db.ForeignKey('enrolment.id', ondelete='CASCADE'), nullable=False)

    lesson_number = db.Column(db.Integer, nullable=False)
    attended = db.Column(db.Boolean, default=False)
    lesson_date = db.Column(db.Date)
    # status = db.Column(db.Boolean, default=True)

    __table_args__ = (
        db.UniqueConstraint('enrolment_id', 'lesson_number'),
    )

我有一条路线可以将多个学生注册到一个班级:

  • 对于每个学生,在Enrolment 中插入一条记录
  • 还插入付款负债和出勤记录
@enrol_bp.route('/', methods=['POST'])
@jwt_required
def enrol():
    c = Class.query.filter_by(id=request.json['class_id']).first()
    if not c:
        return jsonify(message = f'Class {c.id} does not exist'), 404
    student_ids = request.json['student_ids']
    for student_id in student_ids:
        student = Student.query.filter_by(id=student_id).first()
        if not student:
            return jsonify(message = f'Student {student_id} does not exist'), 404
        enrolment = Enrolment(
            class_id=c.id,
            student_id=student.id,
            enrolment_date=datetime.strptime(request.json['enrolment_date'], '%Y-%m-%d')
        )
        db.session.add(enrolment)
        lesson_count = 0
        for term_index, term in enumerate(c.terms):
            payment = Payment(
                enrolment=enrolment,
                number=term_index+1,
                amount=term['lessons'] * term['cost_per_lesson'],
            )
            db.session.add(payment)
            for lesson_index in range(0, term['lessons']):
                attendance = Attendance(
                    enrolment=enrolment,
                    lesson_number=lesson_count+1
                )
                lesson_count += 1
                db.session.add(attendance)
    db.session.commit()
    return jsonify(message = f'Students enrolled')

当我从前端 POST 到 enrol 端点时,我收到主键约束错误 - 这是意外的,因为所有模型都有一个自动递增的整数 PK。

同样奇怪的是,当我不断点击前端的注册时,每个请求都会导致不同的错误。您可以在下面看到,第一次尝试使用id = 90 创建出勤,第二次尝试使用id = 91。我的数据库目前有 280 条出勤记录,所以我想如果我继续点击,它最终会“工作”。

最初,我在创建注册记录时遇到错误,但随着我不断点击,ID 会递增直到它有效,但随后我在付款和出勤时遇到错误。

# Attempt 1
sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "attendance_pkey"
DETAIL:  Key (id)=(90) already exists.

[SQL: INSERT INTO attendance (enrolment_id, lesson_number, attended, lesson_date) VALUES (%(enrolment_id)s, %(lesson_number)s, %(attended)s, %(lesson_date)s) RETURNING attendance.id]
[parameters: {'enrolment_id': 49, 'lesson_number': 1, 'attended': False, 'lesson_date': None}]


# Attempt 2
sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "attendance_pkey"
DETAIL:  Key (id)=(91) already exists.

[SQL: INSERT INTO attendance (enrolment_id, lesson_number, attended, lesson_date) VALUES (%(enrolment_id)s, %(lesson_number)s, %(attended)s, %(lesson_date)s) RETURNING attendance.id]
[parameters: {'enrolment_id': 50, 'lesson_number': 1, 'attended': False, 'lesson_date': None}]

查看 SQL 插入语句,它应该可以工作,因为它没有在其插入语句中指定出席者.id,因此它应该是自动生成的。 RETURNING attendance.id 有问题吗?还是完全是别的东西?

【问题讨论】:

    标签: python sqlalchemy flask-sqlalchemy


    【解决方案1】:

    没关系,这是一个 Postgres 问题,它是由于尝试在没有先清除我的原始数据库的情况下还原数据库,然后决定不打扰完成还原并继续在数据库上工作,而没有意识到还原将数据库留在半完成状态。

    这导致我的主键序列与实际表不同步(即主键序列已通过转储更新,但表数据本身并未更新)。

    有关如何解决此问题的更多信息: postgresql duplicate key violates unique constraint

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 2012-07-15
      • 1970-01-01
      • 2021-04-11
      • 2016-08-24
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多