SqlAlchemy - ForeignKey Verständnisproblem

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
earloop
User
Beiträge: 38
Registriert: Sonntag 11. Oktober 2020, 13:54

Hallo,

wenn ich das richtig verstanden habe, sorgt ein ForeignKey dafür, dass in der Child Tabelle (bei mir: comments) nur Werte eingegeben werden können, die in den Parent Tabellen enthalten sind. So stehts zumindest hier:
https://www.w3schools.com/sql/sql_foreignkey.asp

Ich habe 3 Tabellen: users, articles, comments
Jeder Comment hat nur einen User und nur einen Article, aber jeder Article kann viele Comments von vielen Nutzern haben.

Code: Alles auswählen

from sqlalchemy import Column, Integer, String, create_engine, ForeignKey
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///Database.db', echo = True)
Base = declarative_base()

#tables
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    
class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(String)
    content = Column(String)

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    comment = Column(String)
    article_id = Column(Integer, ForeignKey('articles.id'))
    user_id = Column(Integer, ForeignKey('users.id'))
    
Base.metadata.create_all(engine)

#session
Session = sessionmaker(bind = engine)
session = Session()

#fill tables
user1 = User(name = "user 1")
user2 = User(name = "user 2")
article1 = Article(title = 'title 1', content = 'lorem ipsum 1')
article2 = Article(title = 'title 2', content = 'lorem ipsum 2')
comment1 = Comment(comment = 'coment 1', article_id = 3, user_id = 4)

session.add_all([user1, user2, article1, article2, comment1])
session.commit()
Ich habe 2 user und 2 article angelegt, denen werden jeweils die ids 1 und 2 vergeben. Es gibt also in der ganzen Datenbank keine id, die größer als 2 ist. Trotzdem kann ich einen Comment anlegen, dessen foreign keys größer als 2 sind - diese sind also definitiv nicht vorhanden in den Partent Tabellen.
Ist das nicht ein Widerspruch zur ForeignKey constraint?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wenn ein Test auf Vorhandensein der Foreign-Keys erfolgen soll, dann musst Du das der Datenbank auch mitteilen, denn von alleine passiert das nicht. Dies geschieht beim Anlegen der Tabellen: https://docs.sqlalchemy.org/en/14/core/constraints.html
earloop
User
Beiträge: 38
Registriert: Sonntag 11. Oktober 2020, 13:54

Also mit nullable = False?
Auch wenn ich die Comment Klasse ändere:

Code: Alles auswählen

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    comment = Column(String)
    article_id = Column(Integer, ForeignKey('articles.id'), nullable = False)
    user_id = Column(Integer, ForeignKey('users.id'), nullable = False)
kann ich trotzdem Comments mit ids vergeben, die es im Parent nicht gibt.

Jetzt verstehe ich noch weniger. hier steht:
The FOREIGN KEY constraint prevents invalid data from being inserted into the foreign key column, because it has to be one of the values contained in the parent table.
Warum kann ich dann ids vergeben, die es im Parent nicht gibt?

und was ist der Unterschied zwischen:

Code: Alles auswählen

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    comment = Column(String)
    article_id = Column(Integer, ForeignKey('articles.id'))
    user_id = Column(Integer, ForeignKey('users.id'))
und

Code: Alles auswählen

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    comment = Column(String)
    article_id = Column(Integer)
    user_id = Column(Integer)
Welche Funktion hat das ForeignKey?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

SQLite hat einige Besonderheiten, dazu gehört dass foreign keys nicht validiert werden, es sei den man stellt dass ein. Die SQLite Dokumention erklärt wie dass geht.
earloop
User
Beiträge: 38
Registriert: Sonntag 11. Oktober 2020, 13:54

Also macht es in diesem Fall überhaupt keinen Unterschied, ob ich die Spalte mit oder ohne ForeignKey definiere?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst es doch sinnvoll machen, indem du der Anleitung, die DasIch gepostet hat, folgst.

Aber ohne das zu machen offensichtlich: nein.
Antworten