mirror of
https://github.com/d3vyce/fastapi-toolsets.git
synced 2026-04-16 14:46:24 +02:00
2590 lines
148 KiB
HTML
2590 lines
148 KiB
HTML
|
|
<!doctype html>
|
|
<html lang="en" class="no-js">
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
<meta name="description" content="Production-ready utilities for FastAPI applications.">
|
|
|
|
|
|
<meta name="author" content="d3vyce">
|
|
|
|
|
|
<link rel="canonical" href="https://fastapi-toolsets.d3vyce.fr/v2.4/module/crud/">
|
|
|
|
|
|
<link rel="prev" href="../cli/">
|
|
|
|
|
|
<link rel="next" href="../db/">
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="icon" href="../../assets/images/favicon.png">
|
|
<meta name="generator" content="zensical-0.0.30">
|
|
|
|
|
|
|
|
<title>CRUD - FastAPI Toolsets</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/modern/main.3b031116.min.css">
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/modern/palette.dfe2e883.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,500,500i,700,700i%7CJetbrains+Mono:400,400i,700,700i&display=fallback">
|
|
<style>:root{--md-text-font:"Inter";--md-code-font:"Jetbrains Mono"}</style>
|
|
|
|
|
|
|
|
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,t)=>(e<<5)-e+t.charCodeAt(0)),0),__md_get=(e,t=localStorage,a=__md_scope)=>JSON.parse(t.getItem(a.pathname+"."+e)),__md_set=(e,t,a=localStorage,_=__md_scope)=>{try{a.setItem(_.pathname+"."+e,JSON.stringify(t))}catch(e){}},document.documentElement.setAttribute("data-platform",navigator.platform)</script>
|
|
|
|
|
|
|
|
|
|
|
|
<script
|
|
defer
|
|
src="https://analytics.d3vyce.fr/script.js"
|
|
data-website-id="338b8816-7b99-4c6a-82f3-15595be3fd47"
|
|
></script>
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
|
|
|
|
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
|
<label class="md-overlay" for="__drawer" aria-label="Navigation"></label>
|
|
<div data-md-component="skip">
|
|
|
|
|
|
<a href="#crud" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
</div>
|
|
<div data-md-component="announce">
|
|
|
|
</div>
|
|
|
|
<div data-md-color-scheme="default" data-md-component="outdated" hidden>
|
|
|
|
<aside class="md-banner md-banner--warning">
|
|
<div class="md-banner__inner md-grid md-typeset">
|
|
You're not viewing the latest
|
|
version.
|
|
<a href="../../..">
|
|
<strong>Click here to go to latest.</strong>
|
|
</a>
|
|
|
|
</div>
|
|
<script>var el=document.querySelector("[data-md-component=outdated]"),base=new URL("../.."),outdated=__md_get("__outdated",sessionStorage,base);!0===outdated&&el&&(el.hidden=!1)</script>
|
|
</aside>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<header class="md-header" data-md-component="header">
|
|
<nav class="md-header__inner md-grid" aria-label="Header">
|
|
<a href="../.." title="FastAPI Toolsets" class="md-header__button md-logo" aria-label="FastAPI Toolsets" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-book-open" viewBox="0 0 24 24"><path d="M12 7v14M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
|
|
|
|
</a>
|
|
<label class="md-header__button md-icon" for="__drawer" aria-label="Navigation">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-menu" viewBox="0 0 24 24"><path d="M4 5h16M4 12h16M4 19h16"/></svg>
|
|
</label>
|
|
<div class="md-header__title" data-md-component="header-title">
|
|
<div class="md-header__ellipsis">
|
|
<div class="md-header__topic">
|
|
<span class="md-ellipsis">
|
|
FastAPI Toolsets
|
|
</span>
|
|
</div>
|
|
<div class="md-header__topic" data-md-component="header-topic">
|
|
<span class="md-ellipsis">
|
|
|
|
CRUD
|
|
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<form class="md-header__option" data-md-component="palette">
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="none" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="none" data-md-color-scheme="slate" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-moon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>
|
|
</label>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-header__button md-icon" for="__search" aria-label="Search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-search" viewBox="0 0 24 24"><path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/></svg>
|
|
</label>
|
|
<div class="md-search" data-md-component="search" role="dialog" aria-label="Search">
|
|
<button type="button" class="md-search__button">
|
|
Search
|
|
</button>
|
|
</div>
|
|
|
|
|
|
<div class="md-header__source">
|
|
|
|
<a href="https://github.com/d3vyce/fastapi-toolsets" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
GitHub
|
|
</div>
|
|
</a>
|
|
|
|
</div>
|
|
</nav>
|
|
|
|
</header>
|
|
|
|
<div class="md-container" data-md-component="container">
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
|
<div class="md-grid">
|
|
<ul class="md-tabs__list">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../.." class="md-tabs__link">
|
|
|
|
|
|
Home
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item md-tabs__item--active">
|
|
<a href="../cli/" class="md-tabs__link">
|
|
|
|
|
|
Modules
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../reference/cli/" class="md-tabs__link">
|
|
|
|
|
|
Reference
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../examples/pagination-search/" class="md-tabs__link">
|
|
|
|
|
|
Examples
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../migration/v2/" class="md-tabs__link">
|
|
|
|
|
|
Migration
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="https://github.com/d3vyce/fastapi-toolsets/releases" class="md-tabs__link">
|
|
|
|
|
|
Changelog ↗
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
|
|
|
|
<main class="md-main" data-md-component="main">
|
|
<div class="md-main__inner md-grid">
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
|
<label class="md-nav__title" for="__drawer">
|
|
<a href="../.." title="FastAPI Toolsets" class="md-nav__button md-logo" aria-label="FastAPI Toolsets" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-book-open" viewBox="0 0 24 24"><path d="M12 7v14M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
|
|
|
|
</a>
|
|
FastAPI Toolsets
|
|
</label>
|
|
|
|
<div class="md-nav__source">
|
|
<a href="https://github.com/d3vyce/fastapi-toolsets" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
GitHub
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../.." class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Home
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Modules
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
|
|
<label class="md-nav__title" for="__nav_2">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
|
|
Modules
|
|
|
|
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../cli/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
CLI
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active">
|
|
|
|
<a href="././" class="md-nav__link md-nav__link--active">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
CRUD
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../db/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Database
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../dependencies/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Dependencies
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../exceptions/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Exceptions
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../fixtures/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Fixtures
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../logger/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Logger
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../metrics/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Metrics
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../models/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Models
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../pytest/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Pytest
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../schemas/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Schemas
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Reference
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_3">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
|
|
Reference
|
|
|
|
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/cli/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
CLI
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/crud/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
CRUD
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/db/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Database
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/dependencies/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Dependencies
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/exceptions/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Exceptions
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/fixtures/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Fixtures
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/logger/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Logger
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/metrics/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Metrics
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/models/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Models
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/pytest/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Pytest
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../reference/schemas/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Schemas
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Examples
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_4">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
|
|
Examples
|
|
|
|
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../examples/pagination-search/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Pagination & Search
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Migration
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_5">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
|
|
Migration
|
|
|
|
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../migration/v2/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
v2.0
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="https://github.com/d3vyce/fastapi-toolsets/releases" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Changelog ↗
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
|
|
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
|
<div class="md-sidebar-button__wrapper">
|
|
<label class="md-sidebar-button" for="__toc"></label>
|
|
</div>
|
|
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="On this page">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
On this page
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#overview" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Overview
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#creating-a-crud-class" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Creating a CRUD class
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Creating a CRUD class">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#factory-style" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Factory style
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#subclass-style" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Subclass style
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#adding-custom-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Adding custom methods
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sharing-a-custom-base-across-multiple-models" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Sharing a custom base across multiple models
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#basic-operations" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Basic operations
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#fetching-a-single-record" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Fetching a single record
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#pagination" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Pagination
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Pagination">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#offset-pagination" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Offset pagination
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Offset pagination">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#skipping-the-count-query" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Skipping the COUNT query
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#pagination-params-dependency" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Pagination params dependency
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#cursor-pagination" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Cursor pagination
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Cursor pagination">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#choosing-a-cursor-column" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Choosing a cursor column
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#pagination-params-dependency_1" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Pagination params dependency
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#unified-endpoint-both-strategies" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Unified endpoint (both strategies)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Unified endpoint (both strategies)">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#pagination-params-dependency_2" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Pagination params dependency
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#search" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Search
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Search">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#full-text-search" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Full-text search
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#faceted-search" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Faceted search
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sorting" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Sorting
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#relationship-loading" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Relationship loading
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#many-to-many-relationships" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Many-to-many relationships
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#upsert" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Upsert
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#response-serialization" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Response serialization
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-content" data-md-component="content">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-path" aria-label="Navigation" >
|
|
<ol class="md-path__list">
|
|
|
|
|
|
|
|
|
|
<li class="md-path__item">
|
|
<a href="../.." class="md-path__link">
|
|
|
|
<span class="md-ellipsis">
|
|
Home
|
|
</span>
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-path__item">
|
|
<a href="../cli/" class="md-path__link">
|
|
|
|
<span class="md-ellipsis">
|
|
Modules
|
|
</span>
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ol>
|
|
</nav>
|
|
|
|
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<a href="https://github.com/d3vyce/fastapi-toolsets/raw/master/docs/module/crud.md" title="View source of this page" class="md-content__button md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-file-code-2" viewBox="0 0 24 24"><path d="M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35"/><path d="M14 2v5a1 1 0 0 0 1 1h5M5 16l-3 3 3 3M9 22l3-3-3-3"/></svg>
|
|
</a>
|
|
|
|
|
|
|
|
<h1 id="crud">CRUD<a class="headerlink" href="#crud" title="Permanent link">¶</a></h1>
|
|
<p>Generic async CRUD operations for SQLAlchemy models with search, pagination, and many-to-many support.</p>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p>This module has been coded and tested to be compatible with PostgreSQL only.</p>
|
|
</div>
|
|
<h2 id="overview">Overview<a class="headerlink" href="#overview" title="Permanent link">¶</a></h2>
|
|
<p>The <code>crud</code> module provides <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud"><code>AsyncCrud</code></a>, a base class with a full suite of async database operations, and <a href="../../reference/crud/#fastapi_toolsets.crud.factory.CrudFactory"><code>CrudFactory</code></a>, a convenience function to instantiate it for a given model.</p>
|
|
<h2 id="creating-a-crud-class">Creating a CRUD class<a class="headerlink" href="#creating-a-crud-class" title="Permanent link">¶</a></h2>
|
|
<h3 id="factory-style">Factory style<a class="headerlink" href="#factory-style" title="Permanent link">¶</a></h3>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.crud</span><span class="w"> </span><span class="kn">import</span> <span class="n">CrudFactory</span>
|
|
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
|
|
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
|
|
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="n">UserCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">User</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p><a href="../../reference/crud/#fastapi_toolsets.crud.factory.CrudFactory"><code>CrudFactory</code></a> dynamically creates a class named <code>AsyncUserCrud</code> with <code>User</code> as its model. This is the most concise option for straightforward CRUD with no custom logic.</p>
|
|
<h3 id="subclass-style">Subclass style<a class="headerlink" href="#subclass-style" title="Permanent link">¶</a></h3>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.3.0</code></p>
|
|
</div>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.crud.factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncCrud</span>
|
|
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
|
|
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>
|
|
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="k">class</span><span class="w"> </span><span class="nc">UserCrud</span><span class="p">(</span><span class="n">AsyncCrud</span><span class="p">[</span><span class="n">User</span><span class="p">]):</span>
|
|
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">User</span>
|
|
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a> <span class="n">searchable_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">,</span> <span class="n">User</span><span class="o">.</span><span class="n">email</span><span class="p">]</span>
|
|
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a> <span class="n">default_load_options</span> <span class="o">=</span> <span class="p">[</span><span class="n">selectinload</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">role</span><span class="p">)]</span>
|
|
</span></code></pre></div>
|
|
<p>Subclassing <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud"><code>AsyncCrud</code></a> directly is the preferred style when you need to add custom methods or when the configuration is complex enough to benefit from a named class body. </p>
|
|
<h3 id="adding-custom-methods">Adding custom methods<a class="headerlink" href="#adding-custom-methods" title="Permanent link">¶</a></h3>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">UserCrud</span><span class="p">(</span><span class="n">AsyncCrud</span><span class="p">[</span><span class="n">User</span><span class="p">]):</span>
|
|
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">User</span>
|
|
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>
|
|
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a> <span class="nd">@classmethod</span>
|
|
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_active</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">session</span><span class="p">:</span> <span class="n">AsyncSession</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">User</span><span class="p">]:</span>
|
|
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> <span class="k">return</span> <span class="k">await</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_multi</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">is_active</span> <span class="o">==</span> <span class="kc">True</span><span class="p">])</span>
|
|
</span></code></pre></div>
|
|
<h3 id="sharing-a-custom-base-across-multiple-models">Sharing a custom base across multiple models<a class="headerlink" href="#sharing-a-custom-base-across-multiple-models" title="Permanent link">¶</a></h3>
|
|
<p>Define a generic base class with the shared methods, then subclass it for each model:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
|
|
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.ext.asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncSession</span>
|
|
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">DeclarativeBase</span>
|
|
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.crud.factory</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncCrud</span>
|
|
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a>
|
|
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">DeclarativeBase</span><span class="p">)</span>
|
|
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a>
|
|
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="k">class</span><span class="w"> </span><span class="nc">AuditedCrud</span><span class="p">(</span><span class="n">AsyncCrud</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
|
|
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="sd">"""Base CRUD with custom function"""</span>
|
|
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a>
|
|
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a> <span class="nd">@classmethod</span>
|
|
</span><span id="__span-3-12"><a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_active</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">session</span><span class="p">:</span> <span class="n">AsyncSession</span><span class="p">):</span>
|
|
</span><span id="__span-3-13"><a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a> <span class="k">return</span> <span class="k">await</span> <span class="bp">cls</span><span class="o">.</span><span class="n">get_multi</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="bp">cls</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">is_active</span> <span class="o">==</span> <span class="kc">True</span><span class="p">])</span>
|
|
</span><span id="__span-3-14"><a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a>
|
|
</span><span id="__span-3-15"><a id="__codelineno-3-15" name="__codelineno-3-15" href="#__codelineno-3-15"></a>
|
|
</span><span id="__span-3-16"><a id="__codelineno-3-16" name="__codelineno-3-16" href="#__codelineno-3-16"></a><span class="k">class</span><span class="w"> </span><span class="nc">UserCrud</span><span class="p">(</span><span class="n">AuditedCrud</span><span class="p">[</span><span class="n">User</span><span class="p">]):</span>
|
|
</span><span id="__span-3-17"><a id="__codelineno-3-17" name="__codelineno-3-17" href="#__codelineno-3-17"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">User</span>
|
|
</span><span id="__span-3-18"><a id="__codelineno-3-18" name="__codelineno-3-18" href="#__codelineno-3-18"></a> <span class="n">searchable_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">,</span> <span class="n">User</span><span class="o">.</span><span class="n">email</span><span class="p">]</span>
|
|
</span></code></pre></div>
|
|
<p>You can also use the factory shorthand with the same base by passing <code>base_class</code>:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="n">UserCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">base_class</span><span class="o">=</span><span class="n">AuditedCrud</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h2 id="basic-operations">Basic operations<a class="headerlink" href="#basic-operations" title="Permanent link">¶</a></h2>
|
|
<div class="admonition info">
|
|
<p class="admonition-title"><code>get_or_none</code> added in <code>v2.2</code></p>
|
|
</div>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="c1"># Create</span>
|
|
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">UserCreateSchema</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">"alice"</span><span class="p">))</span>
|
|
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>
|
|
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="c1"># Get one (raises NotFoundError if not found)</span>
|
|
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user_id</span><span class="p">])</span>
|
|
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a>
|
|
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="c1"># Get one or None (never raises)</span>
|
|
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">get_or_none</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user_id</span><span class="p">])</span>
|
|
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a>
|
|
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="c1"># Get first or None</span>
|
|
</span><span id="__span-5-11"><a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">first</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">email</span> <span class="o">==</span> <span class="n">email</span><span class="p">])</span>
|
|
</span><span id="__span-5-12"><a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a>
|
|
</span><span id="__span-5-13"><a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a><span class="c1"># Get multiple</span>
|
|
</span><span id="__span-5-14"><a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a><span class="n">users</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">get_multi</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">is_active</span> <span class="o">==</span> <span class="kc">True</span><span class="p">])</span>
|
|
</span><span id="__span-5-15"><a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a>
|
|
</span><span id="__span-5-16"><a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a><span class="c1"># Update</span>
|
|
</span><span id="__span-5-17"><a id="__codelineno-5-17" name="__codelineno-5-17" href="#__codelineno-5-17"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">UserUpdateSchema</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">"bob"</span><span class="p">),</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user_id</span><span class="p">])</span>
|
|
</span><span id="__span-5-18"><a id="__codelineno-5-18" name="__codelineno-5-18" href="#__codelineno-5-18"></a>
|
|
</span><span id="__span-5-19"><a id="__codelineno-5-19" name="__codelineno-5-19" href="#__codelineno-5-19"></a><span class="c1"># Delete</span>
|
|
</span><span id="__span-5-20"><a id="__codelineno-5-20" name="__codelineno-5-20" href="#__codelineno-5-20"></a><span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user_id</span><span class="p">])</span>
|
|
</span><span id="__span-5-21"><a id="__codelineno-5-21" name="__codelineno-5-21" href="#__codelineno-5-21"></a>
|
|
</span><span id="__span-5-22"><a id="__codelineno-5-22" name="__codelineno-5-22" href="#__codelineno-5-22"></a><span class="c1"># Count / exists</span>
|
|
</span><span id="__span-5-23"><a id="__codelineno-5-23" name="__codelineno-5-23" href="#__codelineno-5-23"></a><span class="n">count</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">is_active</span> <span class="o">==</span> <span class="kc">True</span><span class="p">])</span>
|
|
</span><span id="__span-5-24"><a id="__codelineno-5-24" name="__codelineno-5-24" href="#__codelineno-5-24"></a><span class="n">exists</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">email</span> <span class="o">==</span> <span class="n">email</span><span class="p">])</span>
|
|
</span></code></pre></div>
|
|
<h2 id="fetching-a-single-record">Fetching a single record<a class="headerlink" href="#fetching-a-single-record" title="Permanent link">¶</a></h2>
|
|
<p>Three methods fetch a single record — choose based on how you want to handle the "not found" case and whether you need strict uniqueness:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Method</th>
|
|
<th>Not found</th>
|
|
<th>Multiple results</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>get</code></td>
|
|
<td>raises <code>NotFoundError</code></td>
|
|
<td>raises <code>MultipleResultsFound</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>get_or_none</code></td>
|
|
<td>returns <code>None</code></td>
|
|
<td>raises <code>MultipleResultsFound</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>first</code></td>
|
|
<td>returns <code>None</code></td>
|
|
<td>returns the first match silently</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Use <code>get</code> when the record must exist (e.g. a detail endpoint that should return 404):</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user_id</span><span class="p">])</span>
|
|
</span></code></pre></div>
|
|
<p>Use <code>get_or_none</code> when the record may not exist but you still want strict uniqueness enforcement:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">get_or_none</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">email</span> <span class="o">==</span> <span class="n">email</span><span class="p">])</span>
|
|
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
|
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a> <span class="o">...</span> <span class="c1"># handle missing case without catching an exception</span>
|
|
</span></code></pre></div>
|
|
<p>Use <code>first</code> when you only care about any one match and don't need uniqueness:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">first</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">is_active</span> <span class="o">==</span> <span class="kc">True</span><span class="p">])</span>
|
|
</span></code></pre></div>
|
|
<h2 id="pagination">Pagination<a class="headerlink" href="#pagination" title="Permanent link">¶</a></h2>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v1.1</code> (only offset_pagination via <code>paginate</code> if <code><v1.1</code>)</p>
|
|
</div>
|
|
<p>Three pagination methods are available. All return a typed response whose <code>pagination_type</code> field tells clients which strategy was used.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th><code>offset_paginate</code></th>
|
|
<th><code>cursor_paginate</code></th>
|
|
<th><code>paginate</code></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Return type</td>
|
|
<td><code>OffsetPaginatedResponse</code></td>
|
|
<td><code>CursorPaginatedResponse</code></td>
|
|
<td>either, based on <code>pagination_type</code> param</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Total count</td>
|
|
<td>Yes</td>
|
|
<td>No</td>
|
|
<td>/</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Jump to arbitrary page</td>
|
|
<td>Yes</td>
|
|
<td>No</td>
|
|
<td>/</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Performance on deep pages</td>
|
|
<td>Degrades</td>
|
|
<td>Constant</td>
|
|
<td>/</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Stable under concurrent inserts</td>
|
|
<td>No</td>
|
|
<td>Yes</td>
|
|
<td>/</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Use case</td>
|
|
<td>Admin panels, numbered pagination</td>
|
|
<td>Feeds, APIs, infinite scroll</td>
|
|
<td>single endpoint, both strategies</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3 id="offset-pagination">Offset pagination<a class="headerlink" href="#offset-pagination" title="Permanent link">¶</a></h3>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_users</span><span class="p">(</span>
|
|
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a> <span class="n">items_per_page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span>
|
|
</span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a> <span class="n">page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
|
|
</span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-9-7"><a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-9-8"><a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-9-9"><a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-9-10"><a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-9-11"><a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-9-12"><a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>The <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.offset_paginate"><code>offset_paginate</code></a> method returns an <a href="../../reference/schemas/#fastapi_toolsets.schemas.OffsetPaginatedResponse"><code>OffsetPaginatedResponse</code></a>:</p>
|
|
<div class="language-json highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="p">{</span>
|
|
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SUCCESS"</span><span class="p">,</span>
|
|
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="nt">"pagination_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"offset"</span><span class="p">,</span>
|
|
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"..."</span><span class="p">],</span>
|
|
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="nt">"pagination"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
</span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="nt">"total_count"</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span>
|
|
</span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="w"> </span><span class="nt">"pages"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
|
|
</span><span id="__span-10-8"><a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="w"> </span><span class="nt">"page"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
|
|
</span><span id="__span-10-9"><a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="w"> </span><span class="nt">"items_per_page"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
|
</span><span id="__span-10-10"><a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="w"> </span><span class="nt">"has_more"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
|
</span><span id="__span-10-11"><a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="p">}</span>
|
|
</span><span id="__span-10-12"><a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="p">}</span>
|
|
</span></code></pre></div>
|
|
<h4 id="skipping-the-count-query">Skipping the COUNT query<a class="headerlink" href="#skipping-the-count-query" title="Permanent link">¶</a></h4>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.4.1</code></p>
|
|
</div>
|
|
<p>By default <code>offset_paginate</code> runs two queries: one for the page items and one <code>COUNT(*)</code> for <code>total_count</code>. On large tables the <code>COUNT</code> can be expensive. Pass <code>include_total=False</code> to skip it:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a> <span class="n">include_total</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h4 id="pagination-params-dependency">Pagination params dependency<a class="headerlink" href="#pagination-params-dependency" title="Permanent link">¶</a></h4>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.4.1</code></p>
|
|
</div>
|
|
<p>Use <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.offset_params"><code>offset_params()</code></a> to generate a FastAPI dependency that injects <code>page</code> and <code>items_per_page</code> from query parameters with configurable defaults and a <code>max_page_size</code> cap:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">Depends</span>
|
|
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>
|
|
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-12-5"><a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-12-6"><a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-12-7"><a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a> <span class="n">params</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">dict</span><span class="p">,</span> <span class="n">Depends</span><span class="p">(</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_params</span><span class="p">(</span><span class="n">default_page_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">max_page_size</span><span class="o">=</span><span class="mi">100</span><span class="p">))],</span>
|
|
</span><span id="__span-12-8"><a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-12-9"><a id="__codelineno-12-9" name="__codelineno-12-9" href="#__codelineno-12-9"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">params</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h3 id="cursor-pagination">Cursor pagination<a class="headerlink" href="#cursor-pagination" title="Permanent link">¶</a></h3>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a> <span class="n">cursor</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
|
</span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a> <span class="n">items_per_page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">20</span><span class="p">,</span>
|
|
</span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a><span class="p">)</span> <span class="o">-></span> <span class="n">CursorPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">cursor_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-13-9"><a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a> <span class="n">cursor</span><span class="o">=</span><span class="n">cursor</span><span class="p">,</span>
|
|
</span><span id="__span-13-10"><a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-13-11"><a id="__codelineno-13-11" name="__codelineno-13-11" href="#__codelineno-13-11"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-13-12"><a id="__codelineno-13-12" name="__codelineno-13-12" href="#__codelineno-13-12"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>The <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.cursor_paginate"><code>cursor_paginate</code></a> method returns a <a href="../../reference/schemas/#fastapi_toolsets.schemas.CursorPaginatedResponse"><code>CursorPaginatedResponse</code></a>:</p>
|
|
<div class="language-json highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="p">{</span>
|
|
</span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SUCCESS"</span><span class="p">,</span>
|
|
</span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="w"> </span><span class="nt">"pagination_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cursor"</span><span class="p">,</span>
|
|
</span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"..."</span><span class="p">],</span>
|
|
</span><span id="__span-14-5"><a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a><span class="w"> </span><span class="nt">"pagination"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
</span><span id="__span-14-6"><a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a><span class="w"> </span><span class="nt">"next_cursor"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eyJ2YWx1ZSI6ICIzZjQ3YWM2OS0uLi4ifQ=="</span><span class="p">,</span>
|
|
</span><span id="__span-14-7"><a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a><span class="w"> </span><span class="nt">"prev_cursor"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
|
|
</span><span id="__span-14-8"><a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a><span class="w"> </span><span class="nt">"items_per_page"</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
|
|
</span><span id="__span-14-9"><a id="__codelineno-14-9" name="__codelineno-14-9" href="#__codelineno-14-9"></a><span class="w"> </span><span class="nt">"has_more"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
|
|
</span><span id="__span-14-10"><a id="__codelineno-14-10" name="__codelineno-14-10" href="#__codelineno-14-10"></a><span class="w"> </span><span class="p">}</span>
|
|
</span><span id="__span-14-11"><a id="__codelineno-14-11" name="__codelineno-14-11" href="#__codelineno-14-11"></a><span class="p">}</span>
|
|
</span></code></pre></div>
|
|
<p>Pass <code>next_cursor</code> as the <code>cursor</code> query parameter on the next request to advance to the next page. <code>prev_cursor</code> is set on pages 2+ and points back to the first item of the current page. Both are <code>null</code> when there is no adjacent page.</p>
|
|
<h4 id="choosing-a-cursor-column">Choosing a cursor column<a class="headerlink" href="#choosing-a-cursor-column" title="Permanent link">¶</a></h4>
|
|
<p>The cursor column is set once on <a href="../../reference/crud/#fastapi_toolsets.crud.factory.CrudFactory"><code>CrudFactory</code></a> via the <code>cursor_column</code> parameter. It must be monotonically ordered for stable results:</p>
|
|
<ul>
|
|
<li>Auto-increment integer PKs</li>
|
|
<li>UUID v7 PKs</li>
|
|
<li>Timestamps</li>
|
|
</ul>
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>Random UUID v4 PKs are <strong>not</strong> suitable as cursor columns because their ordering is non-deterministic.</p>
|
|
</div>
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p><code>cursor_column</code> is required. Calling <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.cursor_paginate"><code>cursor_paginate</code></a> on a CRUD class that has no <code>cursor_column</code> configured raises a <code>ValueError</code>.</p>
|
|
</div>
|
|
<p>The cursor value is URL-safe base64-encoded (no padding) when returned to the client and decoded back to the correct Python type on the next request. The following SQLAlchemy column types are supported:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>SQLAlchemy type</th>
|
|
<th>Python type</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>Integer</code>, <code>BigInteger</code>, <code>SmallInteger</code></td>
|
|
<td><code>int</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>Uuid</code></td>
|
|
<td><code>uuid.UUID</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>DateTime</code></td>
|
|
<td><code>datetime.datetime</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>Date</code></td>
|
|
<td><code>datetime.date</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>Float</code>, <code>Numeric</code></td>
|
|
<td><code>decimal.Decimal</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="c1"># Paginate by the primary key</span>
|
|
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="n">PostCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">Post</span><span class="p">,</span> <span class="n">cursor_column</span><span class="o">=</span><span class="n">Post</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
|
|
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>
|
|
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a><span class="c1"># Paginate by a timestamp column instead</span>
|
|
</span><span id="__span-15-5"><a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a><span class="n">PostCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">Post</span><span class="p">,</span> <span class="n">cursor_column</span><span class="o">=</span><span class="n">Post</span><span class="o">.</span><span class="n">created_at</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h4 id="pagination-params-dependency_1">Pagination params dependency<a class="headerlink" href="#pagination-params-dependency_1" title="Permanent link">¶</a></h4>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.4.1</code></p>
|
|
</div>
|
|
<p>Use <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.cursor_params"><code>cursor_params()</code></a> to inject <code>cursor</code> and <code>items_per_page</code> from query parameters with a <code>max_page_size</code> cap:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
</span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">Depends</span>
|
|
</span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a>
|
|
</span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-16-5"><a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-16-6"><a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-16-7"><a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a> <span class="n">params</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">dict</span><span class="p">,</span> <span class="n">Depends</span><span class="p">(</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">cursor_params</span><span class="p">(</span><span class="n">default_page_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">max_page_size</span><span class="o">=</span><span class="mi">100</span><span class="p">))],</span>
|
|
</span><span id="__span-16-8"><a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a><span class="p">)</span> <span class="o">-></span> <span class="n">CursorPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-16-9"><a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">cursor_paginate</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">params</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h3 id="unified-endpoint-both-strategies">Unified endpoint (both strategies)<a class="headerlink" href="#unified-endpoint-both-strategies" title="Permanent link">¶</a></h3>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.3.0</code></p>
|
|
</div>
|
|
<p><a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.paginate"><code>paginate()</code></a> dispatches to <code>offset_paginate</code> or <code>cursor_paginate</code> based on a <code>pagination_type</code> query parameter, letting you expose <strong>one endpoint</strong> that supports both strategies. The <code>pagination_type</code> field in the response tells clients which strategy was used, enabling frontend discriminated-union typing.</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.crud</span><span class="w"> </span><span class="kn">import</span> <span class="n">PaginationType</span>
|
|
</span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.schemas</span><span class="w"> </span><span class="kn">import</span> <span class="n">PaginatedResponse</span>
|
|
</span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>
|
|
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-17-6"><a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-17-7"><a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a> <span class="n">pagination_type</span><span class="p">:</span> <span class="n">PaginationType</span> <span class="o">=</span> <span class="n">PaginationType</span><span class="o">.</span><span class="n">OFFSET</span><span class="p">,</span>
|
|
</span><span id="__span-17-8"><a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a> <span class="n">page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">ge</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s2">"Current page (offset only)"</span><span class="p">),</span>
|
|
</span><span id="__span-17-9"><a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a> <span class="n">cursor</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s2">"Cursor token (cursor only)"</span><span class="p">),</span>
|
|
</span><span id="__span-17-10"><a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a> <span class="n">items_per_page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">ge</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mi">100</span><span class="p">),</span>
|
|
</span><span id="__span-17-11"><a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a><span class="p">)</span> <span class="o">-></span> <span class="n">PaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-17-12"><a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">paginate</span><span class="p">(</span>
|
|
</span><span id="__span-17-13"><a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a> <span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-17-14"><a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a> <span class="n">pagination_type</span><span class="o">=</span><span class="n">pagination_type</span><span class="p">,</span>
|
|
</span><span id="__span-17-15"><a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-17-16"><a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a> <span class="n">cursor</span><span class="o">=</span><span class="n">cursor</span><span class="p">,</span>
|
|
</span><span id="__span-17-17"><a id="__codelineno-17-17" name="__codelineno-17-17" href="#__codelineno-17-17"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-17-18"><a id="__codelineno-17-18" name="__codelineno-17-18" href="#__codelineno-17-18"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-17-19"><a id="__codelineno-17-19" name="__codelineno-17-19" href="#__codelineno-17-19"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<div class="language-text highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>GET /users?pagination_type=offset&page=2&items_per_page=10
|
|
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>GET /users?pagination_type=cursor&cursor=eyJ2YWx1ZSI6...&items_per_page=10
|
|
</span></code></pre></div>
|
|
<h4 id="pagination-params-dependency_2">Pagination params dependency<a class="headerlink" href="#pagination-params-dependency_2" title="Permanent link">¶</a></h4>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.4.1</code></p>
|
|
</div>
|
|
<p>Use <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.paginate_params"><code>paginate_params()</code></a> to inject all parameters at once with configurable defaults and a <code>max_page_size</code> cap:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
</span><span id="__span-19-2"><a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">Depends</span>
|
|
</span><span id="__span-19-3"><a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.schemas</span><span class="w"> </span><span class="kn">import</span> <span class="n">PaginatedResponse</span>
|
|
</span><span id="__span-19-4"><a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a>
|
|
</span><span id="__span-19-5"><a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-19-6"><a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-19-7"><a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-19-8"><a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a> <span class="n">params</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">dict</span><span class="p">,</span> <span class="n">Depends</span><span class="p">(</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">paginate_params</span><span class="p">(</span><span class="n">default_page_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">max_page_size</span><span class="o">=</span><span class="mi">100</span><span class="p">))],</span>
|
|
</span><span id="__span-19-9"><a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a><span class="p">)</span> <span class="o">-></span> <span class="n">PaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-19-10"><a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">paginate</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">params</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h2 id="search">Search<a class="headerlink" href="#search" title="Permanent link">¶</a></h2>
|
|
<p>Two search strategies are available, both compatible with <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.offset_paginate"><code>offset_paginate</code></a> and <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.cursor_paginate"><code>cursor_paginate</code></a>.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Full-text search</th>
|
|
<th>Faceted search</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Input</td>
|
|
<td>Free-text string</td>
|
|
<td>Exact column values</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Relationship support</td>
|
|
<td>Yes</td>
|
|
<td>Yes</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Use case</td>
|
|
<td>Search bars</td>
|
|
<td>Filter dropdowns</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">You can use both search strategies in the same endpoint!</p>
|
|
</div>
|
|
<h3 id="full-text-search">Full-text search<a class="headerlink" href="#full-text-search" title="Permanent link">¶</a></h3>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v2.2.1</code></p>
|
|
<p>The model's primary key is always included in <code>searchable_fields</code> automatically, so searching by ID works out of the box without any configuration. When no <code>searchable_fields</code> are declared, only the primary key is searched.</p>
|
|
</div>
|
|
<p>Declare <code>searchable_fields</code> on the CRUD class. Relationship traversal is supported via tuples:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="n">PostCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">Post</span><span class="p">,</span>
|
|
</span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a> <span class="n">searchable_fields</span><span class="o">=</span><span class="p">[</span>
|
|
</span><span id="__span-20-4"><a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a> <span class="n">Post</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
|
|
</span><span id="__span-20-5"><a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a> <span class="n">Post</span><span class="o">.</span><span class="n">content</span><span class="p">,</span>
|
|
</span><span id="__span-20-6"><a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a> <span class="p">(</span><span class="n">Post</span><span class="o">.</span><span class="n">author</span><span class="p">,</span> <span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">),</span> <span class="c1"># search across relationship</span>
|
|
</span><span id="__span-20-7"><a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a> <span class="p">],</span>
|
|
</span><span id="__span-20-8"><a id="__codelineno-20-8" name="__codelineno-20-8" href="#__codelineno-20-8"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>You can override <code>searchable_fields</code> per call with <code>search_fields</code>:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-21-3"><a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a> <span class="n">search_fields</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">country</span><span class="p">],</span>
|
|
</span><span id="__span-21-4"><a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>This allows searching with both <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.offset_paginate"><code>offset_paginate</code></a> and <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.cursor_paginate"><code>cursor_paginate</code></a>:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_users</span><span class="p">(</span>
|
|
</span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-22-4"><a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a> <span class="n">items_per_page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span>
|
|
</span><span id="__span-22-5"><a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a> <span class="n">page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
|
|
</span><span id="__span-22-6"><a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a> <span class="n">search</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
|
</span><span id="__span-22-7"><a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-22-8"><a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-22-9"><a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-22-10"><a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-22-11"><a id="__codelineno-22-11" name="__codelineno-22-11" href="#__codelineno-22-11"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-22-12"><a id="__codelineno-22-12" name="__codelineno-22-12" href="#__codelineno-22-12"></a> <span class="n">search</span><span class="o">=</span><span class="n">search</span><span class="p">,</span>
|
|
</span><span id="__span-22-13"><a id="__codelineno-22-13" name="__codelineno-22-13" href="#__codelineno-22-13"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-22-14"><a id="__codelineno-22-14" name="__codelineno-22-14" href="#__codelineno-22-14"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_users</span><span class="p">(</span>
|
|
</span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-23-4"><a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a> <span class="n">cursor</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
|
</span><span id="__span-23-5"><a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a> <span class="n">items_per_page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span>
|
|
</span><span id="__span-23-6"><a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a> <span class="n">search</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
|
</span><span id="__span-23-7"><a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a><span class="p">)</span> <span class="o">-></span> <span class="n">CursorPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-23-8"><a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">cursor_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-23-9"><a id="__codelineno-23-9" name="__codelineno-23-9" href="#__codelineno-23-9"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-23-10"><a id="__codelineno-23-10" name="__codelineno-23-10" href="#__codelineno-23-10"></a> <span class="n">items_per_page</span><span class="o">=</span><span class="n">items_per_page</span><span class="p">,</span>
|
|
</span><span id="__span-23-11"><a id="__codelineno-23-11" name="__codelineno-23-11" href="#__codelineno-23-11"></a> <span class="n">cursor</span><span class="o">=</span><span class="n">cursor</span><span class="p">,</span>
|
|
</span><span id="__span-23-12"><a id="__codelineno-23-12" name="__codelineno-23-12" href="#__codelineno-23-12"></a> <span class="n">search</span><span class="o">=</span><span class="n">search</span><span class="p">,</span>
|
|
</span><span id="__span-23-13"><a id="__codelineno-23-13" name="__codelineno-23-13" href="#__codelineno-23-13"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-23-14"><a id="__codelineno-23-14" name="__codelineno-23-14" href="#__codelineno-23-14"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h3 id="faceted-search">Faceted search<a class="headerlink" href="#faceted-search" title="Permanent link">¶</a></h3>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v1.2</code></p>
|
|
</div>
|
|
<p>Declare <code>facet_fields</code> on the CRUD class to return distinct column values alongside paginated results. This is useful for populating filter dropdowns or building faceted search UIs.</p>
|
|
<p>Facet fields use the same syntax as <code>searchable_fields</code> — direct columns or relationship tuples:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><span class="n">UserCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">User</span><span class="p">,</span>
|
|
</span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a> <span class="n">facet_fields</span><span class="o">=</span><span class="p">[</span>
|
|
</span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a> <span class="n">User</span><span class="o">.</span><span class="n">status</span><span class="p">,</span>
|
|
</span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a> <span class="n">User</span><span class="o">.</span><span class="n">country</span><span class="p">,</span>
|
|
</span><span id="__span-24-6"><a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a> <span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">role</span><span class="p">,</span> <span class="n">Role</span><span class="o">.</span><span class="n">name</span><span class="p">),</span> <span class="c1"># value from a related model</span>
|
|
</span><span id="__span-24-7"><a id="__codelineno-24-7" name="__codelineno-24-7" href="#__codelineno-24-7"></a> <span class="p">],</span>
|
|
</span><span id="__span-24-8"><a id="__codelineno-24-8" name="__codelineno-24-8" href="#__codelineno-24-8"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>You can override <code>facet_fields</code> per call:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a> <span class="n">facet_fields</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">country</span><span class="p">],</span>
|
|
</span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>The distinct values are returned in the <code>filter_attributes</code> field of <a href="../../reference/schemas/#fastapi_toolsets.schemas.PaginatedResponse"><code>PaginatedResponse</code></a>:</p>
|
|
<div class="language-json highlight"><pre><span></span><code><span id="__span-26-1"><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="p">{</span>
|
|
</span><span id="__span-26-2"><a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"SUCCESS"</span><span class="p">,</span>
|
|
</span><span id="__span-26-3"><a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a><span class="w"> </span><span class="nt">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"..."</span><span class="p">],</span>
|
|
</span><span id="__span-26-4"><a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a><span class="w"> </span><span class="nt">"pagination"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"..."</span><span class="w"> </span><span class="p">},</span>
|
|
</span><span id="__span-26-5"><a id="__codelineno-26-5" name="__codelineno-26-5" href="#__codelineno-26-5"></a><span class="w"> </span><span class="nt">"filter_attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
</span><span id="__span-26-6"><a id="__codelineno-26-6" name="__codelineno-26-6" href="#__codelineno-26-6"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"active"</span><span class="p">,</span><span class="w"> </span><span class="s2">"inactive"</span><span class="p">],</span>
|
|
</span><span id="__span-26-7"><a id="__codelineno-26-7" name="__codelineno-26-7" href="#__codelineno-26-7"></a><span class="w"> </span><span class="nt">"country"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"DE"</span><span class="p">,</span><span class="w"> </span><span class="s2">"FR"</span><span class="p">,</span><span class="w"> </span><span class="s2">"US"</span><span class="p">],</span>
|
|
</span><span id="__span-26-8"><a id="__codelineno-26-8" name="__codelineno-26-8" href="#__codelineno-26-8"></a><span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"admin"</span><span class="p">,</span><span class="w"> </span><span class="s2">"editor"</span><span class="p">,</span><span class="w"> </span><span class="s2">"viewer"</span><span class="p">]</span>
|
|
</span><span id="__span-26-9"><a id="__codelineno-26-9" name="__codelineno-26-9" href="#__codelineno-26-9"></a><span class="w"> </span><span class="p">}</span>
|
|
</span><span id="__span-26-10"><a id="__codelineno-26-10" name="__codelineno-26-10" href="#__codelineno-26-10"></a><span class="p">}</span>
|
|
</span></code></pre></div>
|
|
<p>Use <code>filter_by</code> to pass the client's chosen filter values directly — no need to build SQLAlchemy conditions by hand. Any unknown key raises <a href="../../reference/exceptions/#fastapi_toolsets.exceptions.exceptions.InvalidFacetFilterError"><code>InvalidFacetFilterError</code></a>.</p>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">The keys in <code>filter_by</code> are the same keys the client received in <code>filter_attributes</code>.</p>
|
|
<p>Keys are normally the terminal <code>column.key</code> (e.g. <code>"name"</code> for <code>Role.name</code>). When two facet fields share the same column key (e.g. <code>(Build.project, Project.name)</code> and <code>(Build.os, Os.name)</code>), the relationship name is prepended automatically: <code>"project__name"</code> and <code>"os__name"</code>.</p>
|
|
</div>
|
|
<p><code>filter_by</code> and <code>filters</code> can be combined — both are applied with AND logic.</p>
|
|
<p>Use <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.filter_params"><code>filter_params()</code></a> to generate a dict with the facet filter values from the query parameters:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-27-1"><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
</span><span id="__span-27-2"><a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a>
|
|
</span><span id="__span-27-3"><a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">Depends</span>
|
|
</span><span id="__span-27-4"><a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a>
|
|
</span><span id="__span-27-5"><a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a><span class="n">UserCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-27-6"><a id="__codelineno-27-6" name="__codelineno-27-6" href="#__codelineno-27-6"></a> <span class="n">model</span><span class="o">=</span><span class="n">User</span><span class="p">,</span>
|
|
</span><span id="__span-27-7"><a id="__codelineno-27-7" name="__codelineno-27-7" href="#__codelineno-27-7"></a> <span class="n">facet_fields</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="n">User</span><span class="o">.</span><span class="n">country</span><span class="p">,</span> <span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">role</span><span class="p">,</span> <span class="n">Role</span><span class="o">.</span><span class="n">name</span><span class="p">)],</span>
|
|
</span><span id="__span-27-8"><a id="__codelineno-27-8" name="__codelineno-27-8" href="#__codelineno-27-8"></a><span class="p">)</span>
|
|
</span><span id="__span-27-9"><a id="__codelineno-27-9" name="__codelineno-27-9" href="#__codelineno-27-9"></a>
|
|
</span><span id="__span-27-10"><a id="__codelineno-27-10" name="__codelineno-27-10" href="#__codelineno-27-10"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">,</span> <span class="n">response_model_exclude_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
</span><span id="__span-27-11"><a id="__codelineno-27-11" name="__codelineno-27-11" href="#__codelineno-27-11"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-27-12"><a id="__codelineno-27-12" name="__codelineno-27-12" href="#__codelineno-27-12"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-27-13"><a id="__codelineno-27-13" name="__codelineno-27-13" href="#__codelineno-27-13"></a> <span class="n">page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
|
|
</span><span id="__span-27-14"><a id="__codelineno-27-14" name="__codelineno-27-14" href="#__codelineno-27-14"></a> <span class="n">filter_by</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span> <span class="n">Depends</span><span class="p">(</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">filter_params</span><span class="p">())],</span>
|
|
</span><span id="__span-27-15"><a id="__codelineno-27-15" name="__codelineno-27-15" href="#__codelineno-27-15"></a><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-27-16"><a id="__codelineno-27-16" name="__codelineno-27-16" href="#__codelineno-27-16"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-27-17"><a id="__codelineno-27-17" name="__codelineno-27-17" href="#__codelineno-27-17"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-27-18"><a id="__codelineno-27-18" name="__codelineno-27-18" href="#__codelineno-27-18"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-27-19"><a id="__codelineno-27-19" name="__codelineno-27-19" href="#__codelineno-27-19"></a> <span class="n">filter_by</span><span class="o">=</span><span class="n">filter_by</span><span class="p">,</span>
|
|
</span><span id="__span-27-20"><a id="__codelineno-27-20" name="__codelineno-27-20" href="#__codelineno-27-20"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-27-21"><a id="__codelineno-27-21" name="__codelineno-27-21" href="#__codelineno-27-21"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>Both single-value and multi-value query parameters work:</p>
|
|
<div class="language-text highlight"><pre><span></span><code><span id="__span-28-1"><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a>GET /users?status=active → filter_by={"status": ["active"]}
|
|
</span><span id="__span-28-2"><a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a>GET /users?status=active&country=FR → filter_by={"status": ["active"], "country": ["FR"]}
|
|
</span><span id="__span-28-3"><a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a>GET /users?role=admin&role=editor → filter_by={"role": ["admin", "editor"]} (IN clause)
|
|
</span></code></pre></div>
|
|
<h2 id="sorting">Sorting<a class="headerlink" href="#sorting" title="Permanent link">¶</a></h2>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v1.3</code></p>
|
|
</div>
|
|
<p>Declare <code>order_fields</code> on the CRUD class to expose client-driven column ordering via <code>order_by</code> and <code>order</code> query parameters.</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><span class="n">UserCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">User</span><span class="p">,</span>
|
|
</span><span id="__span-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a> <span class="n">order_fields</span><span class="o">=</span><span class="p">[</span>
|
|
</span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a> <span class="n">User</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
|
</span><span id="__span-29-5"><a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a> <span class="n">User</span><span class="o">.</span><span class="n">created_at</span><span class="p">,</span>
|
|
</span><span id="__span-29-6"><a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a> <span class="p">],</span>
|
|
</span><span id="__span-29-7"><a id="__codelineno-29-7" name="__codelineno-29-7" href="#__codelineno-29-7"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>Call <a href="../../reference/crud/#fastapi_toolsets.crud.factory.AsyncCrud.order_params"><code>order_params()</code></a> to generate a FastAPI dependency that maps the query parameters to an <a href="../../reference/crud/#fastapi_toolsets.crud.factory.OrderByClause"><code>OrderByClause</code></a> expression:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-30-1"><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
</span><span id="__span-30-2"><a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a>
|
|
</span><span id="__span-30-3"><a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">Depends</span>
|
|
</span><span id="__span-30-4"><a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.crud</span><span class="w"> </span><span class="kn">import</span> <span class="n">OrderByClause</span>
|
|
</span><span id="__span-30-5"><a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a>
|
|
</span><span id="__span-30-6"><a id="__codelineno-30-6" name="__codelineno-30-6" href="#__codelineno-30-6"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-30-7"><a id="__codelineno-30-7" name="__codelineno-30-7" href="#__codelineno-30-7"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span>
|
|
</span><span id="__span-30-8"><a id="__codelineno-30-8" name="__codelineno-30-8" href="#__codelineno-30-8"></a> <span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span>
|
|
</span><span id="__span-30-9"><a id="__codelineno-30-9" name="__codelineno-30-9" href="#__codelineno-30-9"></a> <span class="n">order_by</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="n">OrderByClause</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">Depends</span><span class="p">(</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">order_params</span><span class="p">())],</span>
|
|
</span><span id="__span-30-10"><a id="__codelineno-30-10" name="__codelineno-30-10" href="#__codelineno-30-10"></a><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-30-11"><a id="__codelineno-30-11" name="__codelineno-30-11" href="#__codelineno-30-11"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">order_by</span><span class="o">=</span><span class="n">order_by</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>The dependency adds two query parameters to the endpoint:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Parameter</th>
|
|
<th>Type</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>order_by</code></td>
|
|
<td><code>str | null</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>order</code></td>
|
|
<td><code>asc</code> or <code>desc</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="language-text highlight"><pre><span></span><code><span id="__span-31-1"><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a>GET /users?order_by=name&order=asc → ORDER BY users.name ASC
|
|
</span><span id="__span-31-2"><a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a>GET /users?order_by=name&order=desc → ORDER BY users.name DESC
|
|
</span></code></pre></div>
|
|
<p>An unknown <code>order_by</code> value raises <a href="../../reference/exceptions/#fastapi_toolsets.exceptions.exceptions.InvalidOrderFieldError"><code>InvalidOrderFieldError</code></a> (HTTP 422).</p>
|
|
<p>You can also pass <code>order_fields</code> directly to <code>order_params()</code> to override the class-level defaults without modifying them:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-32-1"><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="n">UserOrderParams</span> <span class="o">=</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">order_params</span><span class="p">(</span><span class="n">order_fields</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">name</span><span class="p">])</span>
|
|
</span></code></pre></div>
|
|
<h2 id="relationship-loading">Relationship loading<a class="headerlink" href="#relationship-loading" title="Permanent link">¶</a></h2>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v1.1</code></p>
|
|
</div>
|
|
<p>By default, SQLAlchemy relationships are not loaded unless explicitly requested. Instead of using <code>lazy="selectin"</code> on model definitions (which is implicit and applies globally), define a <code>default_load_options</code> on the CRUD class to control loading strategy explicitly.</p>
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>Avoid using <code>lazy="selectin"</code> on model relationships. It fires silently on every query, cannot be disabled per-call, and can cause unexpected cascading loads through deep relationship chains. Use <code>default_load_options</code> instead.</p>
|
|
</div>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-33-1"><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">selectinload</span>
|
|
</span><span id="__span-33-2"><a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a>
|
|
</span><span id="__span-33-3"><a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a><span class="n">ArticleCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-33-4"><a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a> <span class="n">model</span><span class="o">=</span><span class="n">Article</span><span class="p">,</span>
|
|
</span><span id="__span-33-5"><a id="__codelineno-33-5" name="__codelineno-33-5" href="#__codelineno-33-5"></a> <span class="n">default_load_options</span><span class="o">=</span><span class="p">[</span>
|
|
</span><span id="__span-33-6"><a id="__codelineno-33-6" name="__codelineno-33-6" href="#__codelineno-33-6"></a> <span class="n">selectinload</span><span class="p">(</span><span class="n">Article</span><span class="o">.</span><span class="n">category</span><span class="p">),</span>
|
|
</span><span id="__span-33-7"><a id="__codelineno-33-7" name="__codelineno-33-7" href="#__codelineno-33-7"></a> <span class="n">selectinload</span><span class="p">(</span><span class="n">Article</span><span class="o">.</span><span class="n">tags</span><span class="p">),</span>
|
|
</span><span id="__span-33-8"><a id="__codelineno-33-8" name="__codelineno-33-8" href="#__codelineno-33-8"></a> <span class="p">],</span>
|
|
</span><span id="__span-33-9"><a id="__codelineno-33-9" name="__codelineno-33-9" href="#__codelineno-33-9"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p><code>default_load_options</code> applies automatically to all read operations (<code>get</code>, <code>first</code>, <code>get_multi</code>, <code>offset_paginate</code>, <code>cursor_paginate</code>). When <code>load_options</code> is passed at call-site, it <strong>fully replaces</strong> <code>default_load_options</code> for that query — giving you precise per-call control:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-34-1"><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="c1"># Only loads category, tags are not loaded</span>
|
|
</span><span id="__span-34-2"><a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a><span class="n">article</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ArticleCrud</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
|
</span><span id="__span-34-3"><a id="__codelineno-34-3" name="__codelineno-34-3" href="#__codelineno-34-3"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-34-4"><a id="__codelineno-34-4" name="__codelineno-34-4" href="#__codelineno-34-4"></a> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">Article</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">article_id</span><span class="p">],</span>
|
|
</span><span id="__span-34-5"><a id="__codelineno-34-5" name="__codelineno-34-5" href="#__codelineno-34-5"></a> <span class="n">load_options</span><span class="o">=</span><span class="p">[</span><span class="n">selectinload</span><span class="p">(</span><span class="n">Article</span><span class="o">.</span><span class="n">category</span><span class="p">)],</span>
|
|
</span><span id="__span-34-6"><a id="__codelineno-34-6" name="__codelineno-34-6" href="#__codelineno-34-6"></a><span class="p">)</span>
|
|
</span><span id="__span-34-7"><a id="__codelineno-34-7" name="__codelineno-34-7" href="#__codelineno-34-7"></a>
|
|
</span><span id="__span-34-8"><a id="__codelineno-34-8" name="__codelineno-34-8" href="#__codelineno-34-8"></a><span class="c1"># Loads nothing — useful for write-then-refresh flows or lightweight checks</span>
|
|
</span><span id="__span-34-9"><a id="__codelineno-34-9" name="__codelineno-34-9" href="#__codelineno-34-9"></a><span class="n">articles</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ArticleCrud</span><span class="o">.</span><span class="n">get_multi</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">load_options</span><span class="o">=</span><span class="p">[])</span>
|
|
</span></code></pre></div>
|
|
<h2 id="many-to-many-relationships">Many-to-many relationships<a class="headerlink" href="#many-to-many-relationships" title="Permanent link">¶</a></h2>
|
|
<p>Use <code>m2m_fields</code> to map schema fields containing lists of IDs to SQLAlchemy relationships. The CRUD class resolves and validates all IDs before persisting:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-35-1"><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="n">PostCrud</span> <span class="o">=</span> <span class="n">CrudFactory</span><span class="p">(</span>
|
|
</span><span id="__span-35-2"><a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">Post</span><span class="p">,</span>
|
|
</span><span id="__span-35-3"><a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a> <span class="n">m2m_fields</span><span class="o">=</span><span class="p">{</span><span class="s2">"tag_ids"</span><span class="p">:</span> <span class="n">Post</span><span class="o">.</span><span class="n">tags</span><span class="p">},</span>
|
|
</span><span id="__span-35-4"><a id="__codelineno-35-4" name="__codelineno-35-4" href="#__codelineno-35-4"></a><span class="p">)</span>
|
|
</span><span id="__span-35-5"><a id="__codelineno-35-5" name="__codelineno-35-5" href="#__codelineno-35-5"></a>
|
|
</span><span id="__span-35-6"><a id="__codelineno-35-6" name="__codelineno-35-6" href="#__codelineno-35-6"></a><span class="n">post</span> <span class="o">=</span> <span class="k">await</span> <span class="n">PostCrud</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">PostCreateSchema</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Hello"</span><span class="p">,</span> <span class="n">tag_ids</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]))</span>
|
|
</span></code></pre></div>
|
|
<h2 id="upsert">Upsert<a class="headerlink" href="#upsert" title="Permanent link">¶</a></h2>
|
|
<p>Atomic <code>INSERT ... ON CONFLICT DO UPDATE</code> using PostgreSQL:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-36-1"><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a><span class="k">await</span> <span class="n">UserCrud</span><span class="o">.</span><span class="n">upsert</span><span class="p">(</span>
|
|
</span><span id="__span-36-2"><a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-36-3"><a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a> <span class="n">obj</span><span class="o">=</span><span class="n">UserCreateSchema</span><span class="p">(</span><span class="n">email</span><span class="o">=</span><span class="s2">"alice@example.com"</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">"alice"</span><span class="p">),</span>
|
|
</span><span id="__span-36-4"><a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a> <span class="n">index_elements</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">email</span><span class="p">],</span>
|
|
</span><span id="__span-36-5"><a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a> <span class="n">set_</span><span class="o">=</span><span class="p">{</span><span class="s2">"username"</span><span class="p">},</span>
|
|
</span><span id="__span-36-6"><a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a><span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<h2 id="response-serialization">Response serialization<a class="headerlink" href="#response-serialization" title="Permanent link">¶</a></h2>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Added in <code>v1.1</code></p>
|
|
</div>
|
|
<p>Pass a Pydantic schema class to <code>create</code>, <code>get</code>, <code>update</code>, or <code>offset_paginate</code> to serialize the result directly into that schema and wrap it in a <a href="../../reference/schemas/#fastapi_toolsets.schemas.Response"><code>Response[schema]</code></a> or <a href="../../reference/schemas/#fastapi_toolsets.schemas.PaginatedResponse"><code>PaginatedResponse[schema]</code></a>:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span id="__span-37-1"><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">UserRead</span><span class="p">(</span><span class="n">PydanticBase</span><span class="p">):</span>
|
|
</span><span id="__span-37-2"><a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a> <span class="nb">id</span><span class="p">:</span> <span class="n">UUID</span>
|
|
</span><span id="__span-37-3"><a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a> <span class="n">username</span><span class="p">:</span> <span class="nb">str</span>
|
|
</span><span id="__span-37-4"><a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a>
|
|
</span><span id="__span-37-5"><a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
|
</span><span id="__span-37-6"><a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a> <span class="s2">"/</span><span class="si">{uuid}</span><span class="s2">"</span><span class="p">,</span>
|
|
</span><span id="__span-37-7"><a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a> <span class="n">responses</span><span class="o">=</span><span class="n">generate_error_responses</span><span class="p">(</span><span class="n">NotFoundError</span><span class="p">),</span>
|
|
</span><span id="__span-37-8"><a id="__codelineno-37-8" name="__codelineno-37-8" href="#__codelineno-37-8"></a><span class="p">)</span>
|
|
</span><span id="__span-37-9"><a id="__codelineno-37-9" name="__codelineno-37-9" href="#__codelineno-37-9"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_user</span><span class="p">(</span><span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="n">UUID</span><span class="p">)</span> <span class="o">-></span> <span class="n">Response</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-37-10"><a id="__codelineno-37-10" name="__codelineno-37-10" href="#__codelineno-37-10"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">crud</span><span class="o">.</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
|
</span><span id="__span-37-11"><a id="__codelineno-37-11" name="__codelineno-37-11" href="#__codelineno-37-11"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-37-12"><a id="__codelineno-37-12" name="__codelineno-37-12" href="#__codelineno-37-12"></a> <span class="n">filters</span><span class="o">=</span><span class="p">[</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">uuid</span><span class="p">],</span>
|
|
</span><span id="__span-37-13"><a id="__codelineno-37-13" name="__codelineno-37-13" href="#__codelineno-37-13"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-37-14"><a id="__codelineno-37-14" name="__codelineno-37-14" href="#__codelineno-37-14"></a> <span class="p">)</span>
|
|
</span><span id="__span-37-15"><a id="__codelineno-37-15" name="__codelineno-37-15" href="#__codelineno-37-15"></a>
|
|
</span><span id="__span-37-16"><a id="__codelineno-37-16" name="__codelineno-37-16" href="#__codelineno-37-16"></a><span class="nd">@router</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
</span><span id="__span-37-17"><a id="__codelineno-37-17" name="__codelineno-37-17" href="#__codelineno-37-17"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">(</span><span class="n">session</span><span class="p">:</span> <span class="n">SessionDep</span><span class="p">,</span> <span class="n">page</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-></span> <span class="n">OffsetPaginatedResponse</span><span class="p">[</span><span class="n">UserRead</span><span class="p">]:</span>
|
|
</span><span id="__span-37-18"><a id="__codelineno-37-18" name="__codelineno-37-18" href="#__codelineno-37-18"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">crud</span><span class="o">.</span><span class="n">UserCrud</span><span class="o">.</span><span class="n">offset_paginate</span><span class="p">(</span>
|
|
</span><span id="__span-37-19"><a id="__codelineno-37-19" name="__codelineno-37-19" href="#__codelineno-37-19"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
|
</span><span id="__span-37-20"><a id="__codelineno-37-20" name="__codelineno-37-20" href="#__codelineno-37-20"></a> <span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span>
|
|
</span><span id="__span-37-21"><a id="__codelineno-37-21" name="__codelineno-37-21" href="#__codelineno-37-21"></a> <span class="n">schema</span><span class="o">=</span><span class="n">UserRead</span><span class="p">,</span>
|
|
</span><span id="__span-37-22"><a id="__codelineno-37-22" name="__codelineno-37-22" href="#__codelineno-37-22"></a> <span class="p">)</span>
|
|
</span></code></pre></div>
|
|
<p>The schema must have <code>from_attributes=True</code> (or inherit from <a href="../../reference/schemas/#fastapi_toolsets.schemas.PydanticBase"><code>PydanticBase</code></a>) so it can be built from SQLAlchemy model instances.</p>
|
|
<hr />
|
|
<p><a href="../../reference/crud/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 7H5a2 2 0 0 0-2 2v8h2v-4h2v4h2V9a2 2 0 0 0-2-2m0 4H5V9h2m7-2h-4v10h2v-4h2a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2m0 4h-2V9h2m6 0v6h1v2h-4v-2h1V9h-1V7h4v2Z"/></svg></span> API Reference</a></p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
|
|
|
|
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
|
|
|
|
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
|
</div>
|
|
|
|
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-circle-arrow-up" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="m16 12-4-4-4 4M12 16V8"/></svg>
|
|
Back to top
|
|
</button>
|
|
|
|
</main>
|
|
|
|
<footer class="md-footer">
|
|
|
|
|
|
|
|
<nav class="md-footer__inner md-grid" aria-label="Footer" >
|
|
|
|
|
|
<a href="../cli/" class="md-footer__link md-footer__link--prev" aria-label="Previous: CLI">
|
|
<div class="md-footer__button md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-arrow-left" viewBox="0 0 24 24"><path d="m12 19-7-7 7-7M19 12H5"/></svg>
|
|
</div>
|
|
<div class="md-footer__title">
|
|
<span class="md-footer__direction">
|
|
Previous
|
|
</span>
|
|
<div class="md-ellipsis">
|
|
CLI
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
|
|
|
|
<a href="../db/" class="md-footer__link md-footer__link--next" aria-label="Next: Database">
|
|
<div class="md-footer__title">
|
|
<span class="md-footer__direction">
|
|
Next
|
|
</span>
|
|
<div class="md-ellipsis">
|
|
Database
|
|
</div>
|
|
</div>
|
|
<div class="md-footer__button md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-arrow-right" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
|
</div>
|
|
</a>
|
|
|
|
</nav>
|
|
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-copyright">
|
|
|
|
<div class="md-copyright__highlight">
|
|
Copyright © 2026 d3vyce
|
|
</div>
|
|
|
|
|
|
Made with
|
|
<a href="https://zensical.org/" target="_blank" rel="noopener">
|
|
Zensical
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
<div class="md-dialog" data-md-component="dialog">
|
|
<div class="md-dialog__inner md-typeset"></div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script id="__config" type="application/json">{"annotate":null,"base":"../..","features":["announce.dismiss","content.action.view","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.sections","navigation.tabs","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.e2d2d235.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":{"alias":true,"default":"stable","provider":"mike"}}</script>
|
|
|
|
|
|
<script src="../../assets/javascripts/bundle.66be65ca.min.js"></script>
|
|
|
|
|
|
</body>
|
|
</html> |