Wie trete ich drei Tabellen mit SQLalchemy und halten alle Spalten in einer der Tabellen?
So, ich habe drei Tabellen:
Klasse defenitions:
engine = create_engine('sqlite://test.db', echo=False)
SQLSession = sessionmaker(bind=engine)
Base = declarative_base()
class Channel(Base):
__tablename__ = 'channel'
id = Column(Integer, primary_key = True)
title = Column(String)
description = Column(String)
link = Column(String)
pubDate = Column(DateTime)
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key = True)
username = Column(String)
password = Column(String)
sessionId = Column(String)
class Subscription(Base):
__tablename__ = 'subscription'
userId = Column(Integer, ForeignKey('user.id'), primary_key=True)
channelId = Column(Integer, ForeignKey('channel.id'), primary_key=True)
HINWEIS: ich weiß, user.Benutzername sollte eindeutig sein müssen, um das zu beheben, und ich bin nicht sicher, warum SQLalchemy schafft eine Reihe von Namen mit Anführungszeichen zu setzen.
Und ich bin versucht zu kommen mit ein Weg, um alle Kanäle, sowie einen Hinweis darauf, welche Kanäle einen bestimmten Benutzer (identifiziert durch den Benutzer.sessionId zusammen mit dem Benutzer.id) hat ein Abonnement auf.
Zum Beispiel, sagen wir, wir haben vier Kanäle: kanal1, kanal2, kanal3, kanal4; Benutzer: user1; wer hat ein Abonnement auf kanal1 und channel4. Die Abfrage für user1 zurückkehren würde, so etwas wie:
channel.id | channel.title | subscribed
---------------------------------------
1 channel1 True
2 channel2 False
3 channel3 False
4 channel4 True
Ist dies eine best-case-Ergebnis, aber da habe ich absolut keine Ahnung wie das zu erreichen ist die abonnierten Rubrik habe ich stattdessen versuchen, den insbesondere die Benutzer-id in den Zeilen, wo der Benutzer ein Abonnement und wo ein Abonnement fehlt, lass es einfach leer.
Datenbank-engine, die ich verwende zusammen mit SQLalchemy atm. ist sqlite3
Ich habe meinen Kopf kratzen über diese jetzt seit zwei Tagen, habe ich kein problem, gemeinsam mit allen drei durch die Abonnement-Tabelle, aber dann alle Kanäle, in denen der Benutzer nicht über ein Abonnement wird weggelassen.
Ich hoffe, ich habe es geschafft, zu beschreiben, mein problem ausreichend, vielen Dank im Voraus.
BEARBEITEN: Managed um dieses Problem zu lösen in einem etwas klobig Weise mit einer sub-Abfrage:
# What a messy SQL query!
stmt = query(Subscription).filter_by(userId = uid()).join((User, Subscription.userId == User.id)).filter_by(sessionId = id()).subquery()
subs = aliased(Subscription, stmt)
results = query(Channel.id, Channel.title, subs.userId).outerjoin((subs, subs.channelId == Channel.id))
Aber ich werde weiter suchen für eine elegantere Lösung, also die Antworten sind immer noch sehr willkommen.
- Können Sie fügen Sie Ihre Modell - /Tabellen-Definitionen? Je nachdem, ob Sie verwenden die declarational mapper, der normal-mapper oder einfachen Tabellen, die syntax unterscheidet sich ein wenig.
- Getan und aktualisierte Frage, das wäre die declarational-mapper wenn ich mich nicht Irre.
- Das ist die declarational mapper in der Tat 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Option-1:
Subscription
ist nur eine viele-zu-viele-relation-Objekt, und ich würde vorschlagen, dass Ihr Modell es als solche dann eher als eine separate Klasse. Sehen Konfigurieren der Viele-zu-Viele-Beziehungen Dokumentation vonSQLAlchemy/declarative
.Modellieren Sie mit der test-code wird:
erzeugt folgende Ausgabe:
Bitte beachten Sie die Verwendung von
eagerload
, die Ausgabe nur 1 SELECT-Anweisung anstelle von 1 für jedeUser
wennchannels
sind gefragt.Option-2:
Aber wenn Sie möchten, halten Sie das Modell und erstellen Sie einfach eine SA-Abfrage-geben Sie die Spalten, wie Sie bitten, folgende Abfrage sollte den job tun:
Die Ausgabe ist absolut die gleiche wie in der option 1 vor.
sessionId
auf Vollständigkeit.unstuck
. In jedem Fall froh, dass ich helfen konnte.Um dies ein wenig easyer ich habe Beziehungen zu Ihr Modell, so können Sie nur Benutzer.Abonnements erhalten Sie alle Abonnements.
session.query(Channel).filter(Channel.subscriptions.any())
funktionieren würde. Kein Wunder eigentlich, es sollten so ausgewählt werden, eine zusätzliche Spalte für Sie zu arbeiten. So etwas wiesession.query(Channel.id, Channel.title, Channel.subscriptions.any().label('subscribed'))
funktionieren sollte.Nicht Abfragen des Benutzers. Abfrage aus dem Kanal.
Diese Weise erhalten Sie alle Kanäle, nicht nur diejenigen, die im Zusammenhang mit der user in Frage stellen.