Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add kwargs to ForeignKey definitions - #610

Closed
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main
Closed

Add kwargs to ForeignKey definitions#610
farzadsbakhtiar wants to merge 1 commit into
fastapi:mainfrom
farzadsbakhtiar:main

Conversation

@farzadsbakhtiar

Copy link
Copy Markdown

ForeignKey definitions in SqlAlchemy accept kwargs such as onupdate and ondelete that determine the behaviour of the foreign key at the DB level. This PR adds the option to provide kwargs to the ForeignKey definition under the hood. In my case, I used it to control delete behaviour when deleting a model that did not maintain back references (relationships) with its child models. Example -- an application where users can have 0 or 1 "Repository":

class Repository(SQLModel, table=True):
id: int = Field(primary_key=True)
...
class User(SQLModel, table=True):
...
name: str
repository_id: int | None = Field(foreign_key='repository.id', foreign_key_kwargs={'ondelete': 'SET NULL'})
repository: Repository | None = Relationship()
# -- first create a user without a repository
user = User(name='some user')
session.add(user)
session.flush()
# -- create and add the repository
rep = Repository()
user.repository = rep
session.add(rep)
session.flush()
session.commit()
# -- now delete the user's repository
session.delete(rep)
session.commit()

If we didn't set the ondelete="SET NULL" option on the user.repository_id foreign key we would get this error:

psycopg2.errors.ForeignKeyViolation: update or delete on table "repository" violates foreign key constraint "user_repository_id_fkey" on table "user". Key (id)=(1) is still referenced from table "user" .

A workaround for this would be to keep a user: User = Relationship(back_populates='repository') attribute which I didn't want to do because in my case it would clutter my model. I'm wondering whether there are more concrete use cases for the foreign_key_kwargs option.

@antont

Copy link
Copy Markdown

I guess this would support this case as well? #436

I don't know if it's the way forward, or not, but am curious about opinions.

@farzadsbakhtiar

Copy link
Copy Markdown
Author

I think so.

@vlntsolo

vlntsolo commented Aug 1, 2023

Copy link
Copy Markdown

Any hints how to properly set ondelete behavior with foreign keys? I'm trying to figure out how to SET NULL when foreign key is being deleted, but couldn't find a solution which wouldn't throw errors.

Django ORM does a great job by exposing model methods, but here with SQLAlchemy, kwargs would also do. Just need a working solution.

@nick-catalist

nick-catalist commented Aug 19, 2023

Copy link
Copy Markdown

@tiangolo Any takes here? There is an issue I'm running into where defining a foreign_key as part of the "sa_column_args" in a BaseModel for a given object (let's say HeroBase) causes the relationships defined in a HeroRead that inherits from it to fail to find the FK. It works if I define it in the foreign_key value at the field level instead of at the sa_column_args level, and it works if I define it in a field with the sa_column_args within HeroRead and not in HeroBase. I'd prefer to do things the "proper" way and keep it in the BaseModel (as its something all my Hero classes want to have), but there is then no way to specify the ondelete kwarg for my FK :(

Though perhaps it would be even better to solve the issue of FKs defined at the sa level not being resolvable by classes that inherit.

@tiangolotiangolo added the feature New feature or request label Oct 22, 2023
@YuriiMotov

Copy link
Copy Markdown
Member

In current version there is ondelete parameter that serves exactly this reason:

repository_id: int|None=Field(
foreign_key="repository.id", ondelete="SET NULL"
)

This is documented here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/

And, if you need to pass other ForeignKey-related parameters, you can use sa_column_args to pass ForeignKey instance configured as you need.

repository_id: int|None=Field(
sa_column_args=[ForeignKey("repository.id", ondelete="SET NULL")]
)

IMO, this way is better since you will have all type hints (as opposed to foreign_key_kwargs).

Having this, I suggest we close this PR.
@thedamnedrhino, thanks for working on this!

@github-actionsgithub-actionsBot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

@tiangolo

Copy link
Copy Markdown
Member

Thanks @YuriiMotov for the clear clarification! 🙌

Agreed with all, yep, for now I'll pass on this one. Thanks! ☕

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflictsAutomatically generated when a PR has a merge conflictfeatureNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@farzadsbakhtiar@antont@vlntsolo@nick-catalist@YuriiMotov@tiangolo