Comments (8)
Indeed! in SQLite the foreign key constraints are disabled by default (https://www.sqlite.org/foreignkeys.html, 2), you have to enable them manually. the simplest way is to listen to the connect
event and enable this option:
from sqlalchemy import event
engine = create_engine("sqlite:///")
event.listen(engine, "connect", lambda c, _: c.execute("PRAGMA foreign_keys = ON"))
from sqlmodel.
Works for me:
from typing import Optional, List
from sqlmodel import (
Field,
Relationship,
SQLModel,
create_engine,
Session,
delete,
)
class Contact(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
invoicing_contact_of: List["Client"] = Relationship(
back_populates="invoicing_contact",
sa_relationship_kwargs={"lazy": "subquery", "passive_deletes": "all"},
)
class Client(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
invoicing_contact_id: int = Field(default=None, foreign_key="contact.id")
invoicing_contact: Contact = Relationship(
back_populates="invoicing_contact_of",
sa_relationship_kwargs={"lazy": "subquery"},
)
engine = create_engine("postgresql://postgres:postgrespw@localhost:55000", echo=True)
SQLModel.metadata.drop_all(engine)
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
contact = Contact()
client = Client(invoicing_contact=contact)
session.add(client)
session.commit()
session.refresh(client)
session.exec(delete(Contact).where(Contact.id == 1))
session.commit()
from sqlmodel.
I think the error came from something else, in my sample code if I try to delete Client
there are no errors.
session.exec(delete(Client).where(Client.id == 1))
session.commit()
from sqlmodel.
The default behavior of SQLAlchemy
when you delete Contact
is to set NULL
in the invoicing_contact_id
field, to avoid this, you need to set passive_deletes='all'
in the relationship field in the Client
model:
class Contact(SQLModel, table=True):
...
invoicing_contact_of: List["Client"] = Relationship(back_populates="invoicing_contact", sa_relationship_kwargs={"lazy": "subquery", "passive_deletes": "all"})
And now you get an error when you try to delete a Contact
that has a relationship with Client
:
sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) update or delete on table "contact" violates foreign key constraint "client_invoicing_contact_id_fkey" on table "client"
DETAIL: Key (id)=(1) is still referenced from table "client".
from sqlmodel.
@meirdev Thanks for the suggestion, it was quite difficult to find documentation on this.
However, I am not getting the desired behavior.
I have modified the model as follows:
class Contact(SQLModel, table=True):
"""An entry in the address book."""
id: Optional[int] = Field(default=None, primary_key=True)
first_name: Optional[str]
last_name: Optional[str]
company: Optional[str]
email: Optional[str]
address_id: Optional[int] = Field(default=None, foreign_key="address.id")
address: Optional[Address] = Relationship(
back_populates="contacts", sa_relationship_kwargs={"lazy": "subquery"}
)
invoicing_contact_of: List["Client"] = Relationship(
back_populates="invoicing_contact",
sa_relationship_kwargs={"lazy": "subquery", "passive_deletes": "all"}
)
Now if I understand correctly, this function is supposed to raise an IntegrityError
if invoicing_contact_of
is not empty:
def delete_by_id(self, entity_type: Type[sqlmodel.SQLModel], entity_id: int):
"""Deletes the entity of the given type with the given id from the database"""
logger.debug(f"deleting {entity_type} with id={entity_id}")
with self.create_session() as session:
session.exec(
sqlmodel.delete(entity_type).where(entity_type.id == entity_id)
)
session.commit()
It doesn't, the deletion proceeds and the respective Client.invoicing_contact
becomes missing.
from sqlmodel.
Strange. Will run the minimal example to investigate. But does it matter that you are using PostgreSQL and I am using SQLite?
from sqlmodel.
@meirdev Now the IntegrityError
is raised. However, the logic is bidirectional:
If I try to delete a Client
I get also an IntegrityError
. But this should be allowed.
2023-01-20 10:08:07.075 | ERROR | core.intent_result:log_message_if_any:44 - (sqlite3.IntegrityError) FOREIGN KEY constraint failed
[SQL: DELETE FROM client WHERE client.id = ?]
[parameters: (1,)]
(Background on this error at: https://sqlalche.me/e/14/gkpj)
NoneType: None
from sqlmodel.
@meirdev I can verify that our minimal examples are working fine. However, in the context of the entire data model, this is not working.
Basic idea of the data model: Project
requires Contract
requires Client
required Contact
.
Trying to delete a Client
raises
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) FOREIGN KEY constraint failed
[SQL: DELETE FROM client WHERE client.id = ?]
[parameters: (1,)]
(Background on this error at: https://sqlalche.me/e/14/gkpj)
and so does trying to delete a Contract
or Project
.
It seems that by adding just this to the Contact
model:
invoicing_contact_of: List["Client"] = Relationship(
back_populates="invoicing_contact",
sa_relationship_kwargs={
"lazy": "subquery",
"passive_deletes": "all", # can't delete contact if it's used in a client
},
)
... I have made every object with a path to an existing Contact
undeletable.
The "FOREIGN KEY contraint failed" message is also unhelpful because it doesn't tell us any details. Is there a way to get more info?
from sqlmodel.
Related Issues (20)
- There is no unique constraint matching given keys (one-to-many, connecting with many-to-many tables) HOT 2
- Preparing for Pydantic v2 release HOT 13
- [Querying] negating `Model.boolean` in `where()` HOT 2
- [M2M] Query dependent incl. `link_model` fields HOT 3
- Could not refresh instance HOT 9
- SQLModel doesn't recognize Relationship between models HOT 1
- Get select with options (selectinload) using response schema HOT 2
- Dose there any better way to write timezone aware datetime field without using the SQLAlchemy ? HOT 3
- Obtaining `TypeError: Cannot pickle 'module' object` on models with many-to-many relationships HOT 2
- Order of columns in the table created does not have 'id' first, despite the order in the SQLModel. Looks like it's prioritising fields with sa_column HOT 3
- Erro ao executar uvicorn.run(...) HOT 1
- Many to many relationship between a table and itself HOT 6
- How to add current date time by default on a table declaration? HOT 13
- Add documentation about how to use the async tools (session, etc) HOT 5
- async relationship bug HOT 9
- 🚀 Roadmap HOT 28
- Internal link failed at create-db-and-table.md
- Field cannot autocompletion when its a SQLModel HOT 6
- Add an overload to the `exec` method with `_Executable` statement for update and delete statements HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sqlmodel.