Wie fügt man eine Zeile mit autoincrement id in eine Multi-Primärschlüssel-Tabelle ein?

Ich schreibe eine turbogears2 Anwendung. Ich habe einen Tisch wie folgt:

class Order(DeclarativeBase): __tablename__ = 'order' # id of order id = Column(Integer, autoincrement=True, primary_key=True) # buyer's id buyer_id = Column(Integer, ForeignKey('user.user_id', onupdate="CASCADE", ondelete="CASCADE"), primary_key=True) 

Ich möchte eine neue Zeile in diese Tabelle einfügen, aber ich habe ein "Field 'order_id' hat keinen Default-Wert" Fehler. Es scheint, dass ich die ID der Ordnung manuell setzen muss, weil ich zwei Primärschlüssel bekam. Meine Frage ist, wie kann ich eine Zeile einfügen, die neue ID automatisch generiert?

Wenn ich id manuell generiere, habe ich ein Problem. Beispielsweise:

 maxId = DBSession.query(func.max(Order)).one()[0] newOrder = Order(id=maxId + 1, buyer_id=xxx) DBSession.add(newOrder) 

Fügen Sie eine neue Bestellung auf diese Weise scheint ok, aber aber wir haben ein Problem, wenn zwei Anfrage diese Code in fast gleichen Zeit laufen.

Wenn es Anforderung a und b gibt diesen Code in folgender Reihenfolge:

 a.maxId = DBSession.query(func.max(Order)).one()[0] b.maxId = DBSession.query(func.max(Order)).one()[0] b.newOrder = Order(id=maxId + 1, buyer_id=xxx) b.DBSession.add(newOrder) a.newOrder = Order(id=maxId + 1, buyer_id=xxx) a.DBSession.add(newOrder) 

Dann könnte die Anfrage a gescheitert werden, da es bereits einen Auftrag mit derselben ID in der Tabelle gibt. Ich kann die Ausnahme fangen und nochmal versuchen. Aber ich frage mich, gibt es einen besseren Weg zu tun?

Manchmal ist die id nicht einfach integer, wir könnten bestellen id wie folgt:

2009090133 Standards für 33. Ordnung am 2009-09-01

In diesem Fall ist autoincrement nicht verwendbar. Also habe ich keine wahl, manuell ordne id zur bestellung Also meine andere Frage ist, gibt es einen besseren Weg als Fang Ausnahme und wiederholen, um eine Zeile mit id einfügen.

2 Solutions collect form web for “Wie fügt man eine Zeile mit autoincrement id in eine Multi-Primärschlüssel-Tabelle ein?”

Sie sollten einen Standardwert für Ihre Spaltendefinitionen verwenden

 id = Column(Integer, default = sqlexpression) 

Wo sqlexpression ein sql Ausdruck sein kann. Hier ist die Dokumentation . Für autoincrement solltest du die sql expression coalesce(select max(order.id) from order,0) + 1 . Für die Leichtigkeit können Sie sqlalchemy.sql.text importieren, damit die ID-Spalte so aussehen könnte

 id = Column(Integer, default = text("coalesce(select max(order.id) from order,0) + 1")) 

Wenn Sie sequentielle Nummern pro Käufer für Ihre Bestellungen wünschen, dann müssen Sie die Transaktionen, die an einen Käufer einfügen, serialisieren. Sie können das tun, indem Sie eine exklusive Sperre für die Käuferreihe erwerben:

 sess.query(Buyer.id).with_lockmode('update').get(xxx) order_id = sess.query(func.max(Order.id)+1).filter_by(buyer_id=xxx).scalar() or 1 sess.add(Order(id=order_id, buyer_id=xxx)) 

Mit diesem Muster, wenn zwei Transaktionen versuchen, Reihenfolge für einen Käufer parallel zu machen, wird einer von ihnen in der ersten Zeile blockieren, bis die andere Transaktion abgeschlossen oder fehlschlägt.

  • Wie man Daten in sqlalchemy nach Liste sortiert
  • Python unittest (mit SQLAlchemy) schreibt / aktualisiert keine Datenbank?
  • Ist es möglich, einen Event-Listener in SQLAlchemy zu erstellen, der übergeordneten Datensatz erstellen kann?
  • Mehrere Domains und Subdomains auf einer einzigen Pyramid-Instanz
  • "Stale Assoziation Proxy, Elternobjekt ist aus dem Bereich" mit Flask-SQLAlchemy gegangen
  • Wie man zwei Unterabfragen in SQLAlchemy und postgresql vereinigt
  • Warum bekomme ich einen 'NameError' mit diesem Import?
  • Kann nicht fangen SQLAlchemy IntegrityError
  • Mapper konnte keine Primärschlüsselspalten zusammenstellen
  • SQLAlchemie: Automatisches Schließen verhindern
  • Import von CSV in Datenbank mit sqlalchemy
  • Python ist die beste Programmiersprache der Welt.