[
  {
    "path": ".github/DISCUSSION_TEMPLATE/questions.yml",
    "content": "labels: [question]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in SQLModel! 🚀\n\n        Please follow these instructions, fill every question, and do every step. 🙏\n\n        I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time.\n\n        I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions.\n\n        All that, on top of all the incredible help provided by a bunch of community members that give a lot of their time to come here and help others.\n\n        If more SQLModel users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).\n\n        By asking questions in a structured way (following this) it will be much easier to help you.\n\n        And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎\n\n        As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓\n  - type: checkboxes\n    id: checks\n    attributes:\n      label: First Check\n      description: Please confirm and check all the following options.\n      options:\n        - label: I added a very descriptive title here.\n          required: true\n        - label: I used the GitHub search to find a similar question and didn't find it.\n          required: true\n        - label: I searched the SQLModel documentation, with the integrated search.\n          required: true\n        - label: I already searched in Google \"How to X in SQLModel\" and didn't find any information.\n          required: true\n        - label: I already read and followed all the tutorial in the docs and didn't find an answer.\n          required: true\n        - label: I already checked if it is not related to SQLModel but to [Pydantic](https://github.com/samuelcolvin/pydantic).\n          required: true\n        - label: I already checked if it is not related to SQLModel but to [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy).\n          required: true\n  - type: checkboxes\n    id: help\n    attributes:\n      label: Commit to Help\n      description: |\n        After submitting this, I commit to one of:\n\n          * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.\n          * I already hit the \"watch\" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.\n          * Review one Pull Request by downloading the code and following all the review process](https://sqlmodel.tiangolo.com/help/#review-pull-requests).\n\n      options:\n        - label: I commit to help with one of those options 👆\n          required: true\n  - type: textarea\n    id: example\n    attributes:\n      label: Example Code\n      description: |\n        Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.\n\n        If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.\n\n      placeholder: |\n        from sqlmodel import Field, Session, SQLModel, create_engine\n\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str\n            secret_name: str\n            age: int | None = None\n\n\n        hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n\n        engine = create_engine(\"sqlite:///database.db\")\n\n\n        SQLModel.metadata.create_all(engine)\n\n        with Session(engine) as session:\n            session.add(hero_1)\n            session.commit()\n            session.refresh(hero_1)\n            print(hero_1)\n      render: python\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Description\n      description: |\n        What is the problem, question, or error?\n\n        Write a short description telling me what you are doing, what you expect to happen, and what is currently happening.\n      placeholder: |\n        * Create a Hero model.\n        * Create a Hero instance.\n        * Save it to a SQLite database.\n        * Check the data with DB Browser for SQLite.\n        * There's only one hero there, but I expected it to include many others recruited by the first one.\n    validations:\n      required: true\n  - type: dropdown\n    id: os\n    attributes:\n      label: Operating System\n      description: What operating system are you on?\n      multiple: true\n      options:\n        - Linux\n        - Windows\n        - macOS\n        - Other\n    validations:\n      required: true\n  - type: textarea\n    id: os-details\n    attributes:\n      label: Operating System Details\n      description: You can add more details about your operating system here, in particular if you chose \"Other\".\n  - type: input\n    id: sqlmodel-version\n    attributes:\n      label: SQLModel Version\n      description: |\n        What SQLModel version are you using?\n\n        You can find the SQLModel version with:\n\n        ```bash\n        python -c \"import sqlmodel; print(sqlmodel.__version__)\"\n        ```\n    validations:\n      required: true\n  - type: input\n    id: python-version\n    attributes:\n      label: Python Version\n      description: |\n        What Python version are you using?\n\n        You can find the Python version with:\n\n        ```bash\n        python --version\n        ```\n    validations:\n      required: true\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional Context\n      description: Add any additional context information or screenshots you think are useful.\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [tiangolo]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Security Contact\n    about: Please report security vulnerabilities to security@tiangolo.com\n  - name: Question or Problem\n    about: Ask a question or ask about a problem in GitHub Discussions.\n    url: https://github.com/fastapi/sqlmodel/discussions/categories/questions\n  - name: Feature Request\n    about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already.\n    url: https://github.com/fastapi/sqlmodel/discussions/categories/questions\n  - name: Show and tell\n    about: Show what you built with SQLModel or to be used with SQLModel.\n    url: https://github.com/fastapi/sqlmodel/discussions/categories/show-and-tell\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/privileged.yml",
    "content": "name: Privileged\ndescription: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in SQLModel! 🚀\n\n        If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/fastapi/sqlmodel/discussions/categories/questions) instead.\n  - type: checkboxes\n    id: privileged\n    attributes:\n      label: Privileged issue\n      description: Confirm that you are allowed to create an issue here.\n      options:\n        - label: I'm @tiangolo or he asked me directly to create an issue here.\n          required: true\n  - type: textarea\n    id: content\n    attributes:\n      label: Issue Content\n      description: Add the content of the issue here.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  # GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    commit-message:\n      prefix: ⬆\n  # Python\n  - package-ecosystem: \"uv\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    commit-message:\n      prefix: ⬆\n"
  },
  {
    "path": ".github/labeler.yml",
    "content": "docs:\n  - all:\n    - changed-files:\n      - any-glob-to-any-file:\n        - docs/**\n        - docs_src/**\n      - all-globs-to-all-files:\n        - '!sqlmodel/**'\n        - '!pyproject.toml'\n\ninternal:\n  - all:\n    - changed-files:\n      - any-glob-to-any-file:\n        - .github/**\n        - scripts/**\n        - .gitignore\n        - .pre-commit-config.yaml\n        - requirements*.txt\n        - uv.lock\n      - all-globs-to-all-files:\n        - '!docs/**'\n        - '!sqlmodel/**'\n        - '!pyproject.toml'\n"
  },
  {
    "path": ".github/workflows/add-to-project.yml",
    "content": "name: Add to Project\n\non:\n  pull_request_target:\n  issues:\n    types:\n      - opened\n      - reopened\n\njobs:\n  add-to-project:\n    name: Add to project\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/add-to-project@v1.0.2\n        with:\n          project-url: https://github.com/orgs/fastapi/projects/2\n          github-token: ${{ secrets.PROJECTS_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/build-docs.yml",
    "content": "name: Build Docs\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\njobs:\n  changes:\n    runs-on: ubuntu-latest\n    # Required permissions\n    permissions:\n      pull-requests: read\n    # Set job outputs to values from filter step\n    outputs:\n      docs: ${{ steps.filter.outputs.docs }}\n    steps:\n    - uses: actions/checkout@v6\n    # For pull requests it's not necessary to checkout the code but for the main branch it is\n    - uses: dorny/paths-filter@v4\n      id: filter\n      with:\n        filters: |\n          docs:\n            - README.md\n            - docs/**\n            - docs_src/**\n            - pyproject.toml\n            - uv.lock\n            - mkdocs.yml\n            - mkdocs.env.yml\n            - .github/workflows/build-docs.yml\n            - .github/workflows/deploy-docs.yml\n            - data/**\n\n  build-docs:\n    needs:\n      - changes\n    if: ${{ needs.changes.outputs.docs == 'true' }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install docs extras\n        run: uv sync --locked --no-dev --group docs\n      - uses: actions/cache@v5\n        with:\n          key: mkdocs-cards-${{ github.ref }}\n          path: .cache\n      - name: Build Docs\n        run: uv run ./scripts/docs.py build\n      - uses: actions/upload-artifact@v7\n        with:\n          name: docs-site\n          path: ./site/**\n          include-hidden-files: true\n\n  # https://github.com/marketplace/actions/alls-green#why\n  docs-all-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - build-docs\n    runs-on: ubuntu-latest\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@release/v1\n        with:\n          jobs: ${{ toJSON(needs) }}\n          allowed-skips: build-docs\n"
  },
  {
    "path": ".github/workflows/deploy-docs.yml",
    "content": "name: Deploy Docs\non:\n  workflow_run:\n    workflows:\n      - Build Docs\n    types:\n      - completed\n\npermissions:\n  deployments: write\n  issues: write\n  pull-requests: write\n  statuses: write\n\njobs:\n  deploy-docs:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install GitHub Actions dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      - name: Deploy Docs Status Pending\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"pending\"\n      - name: Clean site\n        run: |\n          rm -rf ./site\n          mkdir ./site\n      - uses: actions/download-artifact@v8\n        with:\n          path: ./site/\n          pattern: docs-site\n          merge-multiple: true\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          run-id: ${{ github.event.workflow_run.id }}\n      - name: Deploy to Cloudflare Pages\n        # hashFiles returns an empty string if there are no files\n        if: hashFiles('./site/*')\n        id: deploy\n        env:\n          PROJECT_NAME: sqlmodel\n          BRANCH: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'main' && 'main' ) || ( github.event.workflow_run.head_sha ) }}\n        uses: cloudflare/wrangler-action@v3\n        with:\n          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}\n          command: pages deploy ./site --project-name=${{ env.PROJECT_NAME }} --branch=${{ env.BRANCH }}\n      - name: Deploy Docs Status Error\n        if: failure()\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"error\"\n      - name: Comment Deploy\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          DEPLOY_URL: ${{ steps.deploy.outputs.deployment-url }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"success\"\n"
  },
  {
    "path": ".github/workflows/detect-conflicts.yml",
    "content": "name: \"Conflict detector\"\non:\n  push:\n  pull_request_target:\n    types: [synchronize]\n\njobs:\n  main:\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check if PRs have merge conflicts\n        uses: eps1lon/actions-label-merge-conflict@v3\n        with:\n          dirtyLabel: \"conflicts\"\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          commentOnDirty: \"This pull request has a merge conflict that needs to be resolved.\"\n"
  },
  {
    "path": ".github/workflows/issue-manager.yml",
    "content": "name: Issue Manager\n\non:\n  schedule:\n    - cron: \"13 18 * * *\"\n  issue_comment:\n    types:\n      - created\n  issues:\n    types:\n      - labeled\n  pull_request_target:\n    types:\n      - labeled\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  issue-manager:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: tiangolo/issue-manager@0.6.0\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          config: >\n            {\n              \"answered\": {\n                \"delay\": 864000,\n                \"message\": \"Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.\"\n              },\n              \"waiting\": {\n                \"delay\": 2628000,\n                \"message\": \"As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.\",\n                \"reminder\": {\n                    \"before\": \"P3D\",\n                    \"message\": \"Heads-up: this will be closed in 3 days unless there's new activity.\"\n                }\n              },\n              \"invalid\": {\n                \"delay\": 0,\n                \"message\": \"This was marked as invalid and will be closed now. If this is an error, please provide additional details.\"\n              },\n              \"maybe-ai\": {\n                \"delay\": 0,\n                \"message\": \"This was marked as potentially AI generated and will be closed now. If this is an error, please provide additional details, make sure to read the docs about contributing and AI.\"\n              }\n            }\n"
  },
  {
    "path": ".github/workflows/labeler.yml",
    "content": "name: Labels\non:\n  pull_request_target:\n    types:\n      - opened\n      - synchronize\n      - reopened\n      # For label-checker\n      - labeled\n      - unlabeled\n\njobs:\n  labeler:\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/labeler@v6\n      if: ${{ github.event.action != 'labeled' && github.event.action != 'unlabeled' }}\n    - run: echo \"Done adding labels\"\n  # Run this after labeler applied labels\n  check-labels:\n    needs:\n      - labeler\n    permissions:\n      pull-requests: read\n    runs-on: ubuntu-latest\n    steps:\n      - uses: docker://agilepathway/pull-request-label-checker:latest\n        with:\n          one_of: breaking,security,feature,bug,refactor,upgrade,docs,lang-all,internal\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/latest-changes.yml",
    "content": "name: Latest Changes\n\non:\n  pull_request_target:\n    branches:\n      - main\n    types:\n      - closed\n  workflow_dispatch:\n    inputs:\n      number:\n        description: PR number\n        required: true\n      debug_enabled:\n        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'\n        required: false\n        default: 'false'\n\njobs:\n  latest-changes:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          # To allow latest-changes to commit to the main branch\n          token: ${{ secrets.SQLMODEL_LATEST_CHANGES }}\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@v3\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n      - uses: tiangolo/latest-changes@0.4.1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          latest_changes_file: docs/release-notes.md\n          latest_changes_header: '## Latest Changes'\n          end_regex: '^## '\n          debug_logs: true\n          label_header_prefix: '### '\n"
  },
  {
    "path": ".github/workflows/pre-commit.yml",
    "content": "name: pre-commit\n\non:\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\nenv:\n  # Forks and Dependabot don't have access to secrets\n  HAS_SECRETS: ${{ secrets.PRE_COMMIT != '' }}\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@v6\n        name: Checkout PR for own repo\n        if: env.HAS_SECRETS == 'true'\n        with:\n          # To be able to commit it needs to fetch the head of the branch, not the\n          # merge commit\n          ref: ${{ github.head_ref }}\n          # And it needs the full history to be able to compute diffs\n          fetch-depth: 0\n          # A token other than the default GITHUB_TOKEN is needed to be able to trigger CI\n          token: ${{ secrets.PRE_COMMIT }}\n      # pre-commit lite ci needs the default checkout configs to work\n      - uses: actions/checkout@v6\n        name: Checkout PR for fork\n        if: env.HAS_SECRETS == 'false'\n        with:\n        # To be able to commit it needs the head branch of the PR, the remote one\n          ref: ${{ github.event.pull_request.head.sha }}\n          fetch-depth: 0\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked\n      - name: Run prek - pre-commit\n        id: precommit\n        run: uvx prek run --from-ref origin/${GITHUB_BASE_REF} --to-ref HEAD --show-diff-on-failure\n        continue-on-error: true\n      - name: Commit and push changes\n        if: env.HAS_SECRETS == 'true'\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n          git add -A\n          if git diff --staged --quiet; then\n            echo \"No changes to commit\"\n          else\n            git commit -m \"🎨 Auto format\"\n            git push\n          fi\n      - uses: pre-commit-ci/lite-action@v1.1.0\n        if: env.HAS_SECRETS == 'false'\n        with:\n          msg: 🎨 Auto format\n      - name: Error out on pre-commit errors\n        if: steps.precommit.outcome == 'failure'\n        run: exit 1\n\n  # https://github.com/marketplace/actions/alls-green#why\n  pre-commit-alls-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - pre-commit\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@release/v1\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\n\non:\n  release:\n    types:\n      - created\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'\n        required: false\n        default: 'false'\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n      contents: read\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Install uv\n        uses: astral-sh/setup-uv@v7\n      - name: Build distribution\n        run: uv build\n      - name: Publish\n        run: uv publish\n"
  },
  {
    "path": ".github/workflows/smokeshow.yml",
    "content": "name: Smokeshow\n\non:\n  workflow_run:\n    workflows: [Test]\n    types: [completed]\n\npermissions:\n  statuses: write\n\njobs:\n  smokeshow:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - run: uv sync --locked --no-dev --group github-actions\n      - uses: actions/download-artifact@v8\n        with:\n          name: coverage-html\n          path: htmlcov\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          run-id: ${{ github.event.workflow_run.id }}\n      # Try 5 times to upload coverage to smokeshow\n      - name: Upload coverage to Smokeshow\n        run: |\n          for i in 1 2 3 4 5; do\n            if uv run smokeshow upload htmlcov; then\n                echo \"Smokeshow upload success!\"\n                break\n            fi\n            echo \"Smokeshow upload error, sleep 1 sec and try again.\"\n            sleep 1\n          done\n        env:\n          SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}\n          SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 99\n          SMOKESHOW_GITHUB_CONTEXT: coverage\n          SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}\n          SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }}\n"
  },
  {
    "path": ".github/workflows/test-redistribute.yml",
    "content": "name: Test Redistribute\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\njobs:\n  test-redistribute:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Install build dependencies\n        run: pip install build\n      - name: Build source distribution\n        run: python -m build --sdist\n      - name: Decompress source distribution\n        run: |\n          cd dist\n          tar xvf sqlmodel*.tar.gz\n      - name: Install test dependencies\n        run: |\n          cd dist/sqlmodel*/\n          pip install --group tests --editable .\n      - name: Run source distribution tests\n        run: |\n          cd dist/sqlmodel*/\n          bash scripts/test.sh\n      - name: Build wheel distribution\n        run: |\n          cd dist\n          pip wheel --no-deps sqlmodel*.tar.gz\n\n  # https://github.com/marketplace/actions/alls-green#why\n  test-redistribute-alls-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - test-redistribute\n    runs-on: ubuntu-latest\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@release/v1\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    types:\n      - opened\n      - synchronize\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'\n        required: false\n        default: 'false'\n  schedule:\n    # cron every week on monday\n    - cron: \"0 0 * * 1\"\n\nenv:\n  UV_NO_SYNC: true\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ ubuntu-latest, windows-latest, macos-latest ]\n        python-version: [ \"3.14\" ]\n        uv-resolution:\n          - highest\n        include:\n          - os: ubuntu-latest\n            python-version: \"3.10\"\n            uv-resolution: lowest-direct\n          - os: macos-latest\n            python-version: \"3.11\"\n            uv-resolution: highest\n          - os: windows-latest\n            python-version: \"3.12\"\n            uv-resolution: lowest-direct\n          - os: ubuntu-latest\n            python-version: \"3.13\"\n            uv-resolution: highest\n          - os: macos-latest\n            python-version: \"3.13\"\n            uv-resolution: highest\n      fail-fast: false\n    runs-on: ${{ matrix.os }}\n    env:\n      UV_PYTHON: ${{ matrix.python-version }}\n      UV_RESOLUTION: ${{ matrix.uv-resolution }}\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@v3\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n      - name: Install Dependencies\n        run: uv sync --no-dev --group tests\n      - run: mkdir coverage\n      - name: Test\n        run: uv run bash scripts/test.sh\n        env:\n          COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.pydantic-version }}\n          CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}\n      - name: Store coverage files\n        uses: actions/upload-artifact@v7\n        with:\n          name: coverage-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.pydantic-version }}\n          path: coverage\n          include-hidden-files: true\n\n  coverage-combine:\n    needs:\n      - test\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: actions/setup-python@v6\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@v7\n        with:\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Get coverage files\n        uses: actions/download-artifact@v8\n        with:\n          pattern: coverage-*\n          path: coverage\n          merge-multiple: true\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group tests\n      - run: ls -la coverage\n      - run: uv run coverage combine coverage\n      - run: uv run coverage html --title \"Coverage for ${{ github.sha }}\"\n      - name: Store coverage HTML\n        uses: actions/upload-artifact@v7\n        with:\n          name: coverage-html\n          path: htmlcov\n          include-hidden-files: true\n      - run: uv run coverage report --fail-under=99\n\n  # https://github.com/marketplace/actions/alls-green#why\n  alls-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - coverage-combine\n    runs-on: ubuntu-latest\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@release/v1\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n.mypy_cache\n.vscode\n.idea\npoetry.lock\ndist\nhtmlcov\n*.egg-info\n.coverage*\ncoverage.xml\nsite\n*.db\n.cache\n.venv*\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "# See https://pre-commit.com for more information\n# See https://pre-commit.com/hooks.html for more hooks\nrepos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v6.0.0\n    hooks:\n      - id: check-added-large-files\n      - id: check-toml\n      - id: check-yaml\n        args:\n          - --unsafe\n      - id: end-of-file-fixer\n      - id: trailing-whitespace\n\n  - repo: local\n    hooks:\n      - id: local-ruff-check\n        name: ruff check\n        entry: uv run ruff check --force-exclude --fix --exit-non-zero-on-fix\n        require_serial: true\n        language: unsupported\n        types: [python]\n\n      - id: local-ruff-format\n        name: ruff format\n        entry: uv run ruff format --force-exclude --exit-non-zero-on-format\n        require_serial: true\n        language: unsupported\n        types: [python]\n\n      - id: local-mypy\n        name: mypy check\n        entry: uv run mypy sqlmodel tests/test_select_typing.py\n        require_serial: true\n        language: unsupported\n        pass_filenames: false\n\n      - id: generate-select\n        language: unsupported\n        name: generate-select\n        entry: uv run ./scripts/generate_select.py\n        files: ^scripts/generate_select\\.py|sqlmodel/sql/_expression_select_gen\\.py\\.jinja2$\n\n      - id: generate-readme\n        language: unsupported\n        name: generate README.md from index.md\n        entry: uv run ./scripts/docs.py generate-readme\n        files: ^docs/index\\.md|scripts/docs\\.py$\n        pass_filenames: false\n"
  },
  {
    "path": ".python-version",
    "content": "3.10\n"
  },
  {
    "path": "CITATION.cff",
    "content": "# This CITATION.cff file was generated with cffinit.\n# Visit https://bit.ly/cffinit to generate yours today!\n\ncff-version: 1.2.0\ntitle: SQLModel\nmessage: >-\n  If you use this software, please cite it using the\n  metadata from this file.\ntype: software\nauthors:\n  - given-names: Sebastián\n    family-names: Ramírez\n    email: tiangolo@gmail.com\nidentifiers:\nrepository-code: 'https://github.com/fastapi/sqlmodel'\nurl: 'https://sqlmodel.tiangolo.com'\nabstract: >-\n  SQLModel, SQL databases in Python, designed for\n  simplicity, compatibility, and robustness.\nkeywords:\n  - fastapi\n  - pydantic\n  - sqlalchemy\nlicense: MIT\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Please read the [Development - Contributing](https://sqlmodel.tiangolo.com/contributing/) guidelines in the documentation site.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Sebastián Ramírez\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://sqlmodel.tiangolo.com\"><img src=\"https://sqlmodel.tiangolo.com/img/logo-margin/logo-margin-vector.svg#only-light\" alt=\"SQLModel\"></a>\n\n</p>\n<p align=\"center\">\n    <em>SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3ATest+event%3Apush+branch%3Amain\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/test.yml/badge.svg?event=push&branch=main\" alt=\"Test\">\n</a>\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3APublish\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/publish.yml/badge.svg\" alt=\"Publish\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/sqlmodel\" target=\"_blank\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/sqlmodel.svg\" alt=\"Coverage\">\n<a href=\"https://pypi.org/project/sqlmodel\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/v/sqlmodel?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n</p>\n\n---\n\n**Documentation**: <a href=\"https://sqlmodel.tiangolo.com\" target=\"_blank\">https://sqlmodel.tiangolo.com</a>\n\n**Source Code**: <a href=\"https://github.com/fastapi/sqlmodel\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>\n\n---\n\nSQLModel is a library for interacting with <abbr title='Also called \"Relational databases\"'>SQL databases</abbr> from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust.\n\n**SQLModel** is based on Python type annotations, and powered by <a href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\">Pydantic</a> and <a href=\"https://sqlalchemy.org/\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a>.\n\nThe key features are:\n\n* **Intuitive to write**: Great editor support. <abbr title=\"also known as auto-complete, autocompletion, IntelliSense\">Completion</abbr> everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.\n* **Easy to use**: It has sensible defaults and does a lot of work underneath to simplify the code you write.\n* **Compatible**: It is designed to be compatible with **FastAPI**, Pydantic, and SQLAlchemy.\n* **Extensible**: You have all the power of SQLAlchemy and Pydantic underneath.\n* **Short**: Minimize code duplication. A single type annotation does a lot of work. No need to duplicate models in SQLAlchemy and Pydantic.\n\n## Sponsors\n\n<!-- sponsors -->\n\n<a href=\"https://www.govcert.lu\" target=\"_blank\" title=\"This project is being supported by GOVCERT.LU\"><img src=\"https://sqlmodel.tiangolo.com/img/sponsors/govcert.png\"></a>\n\n<!-- /sponsors -->\n\n## SQL Databases in FastAPI\n\n<a href=\"https://fastapi.tiangolo.com\" target=\"_blank\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" style=\"width: 20%;\"></a>\n\n**SQLModel** is designed to simplify interacting with SQL databases in <a href=\"https://fastapi.tiangolo.com\" class=\"external-link\" target=\"_blank\">FastAPI</a> applications, it was created by the same <a href=\"https://tiangolo.com/\" class=\"external-link\" target=\"_blank\">author</a>. 😁\n\nIt combines SQLAlchemy and Pydantic and tries to simplify the code you write as much as possible, allowing you to reduce the **code duplication to a minimum**, but while getting the **best developer experience** possible.\n\n**SQLModel** is, in fact, a thin layer on top of **Pydantic** and **SQLAlchemy**, carefully designed to be compatible with both.\n\n## Requirements\n\nA recent and currently supported <a href=\"https://www.python.org/downloads/\" class=\"external-link\" target=\"_blank\">version of Python</a>.\n\nAs **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel.\n\n## Installation\n\nMake sure you create a <a href=\"https://sqlmodel.tiangolo.com/virtual-environments/\" class=\"external-link\" target=\"_blank\">virtual environment</a>, activate it, and then install SQLModel, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\nSuccessfully installed sqlmodel\n```\n\n</div>\n\n## Example\n\nFor an introduction to databases, SQL, and everything else, see the <a href=\"https://sqlmodel.tiangolo.com/databases/\" target=\"_blank\">SQLModel documentation</a>.\n\nHere's a quick example. ✨\n\n### A SQL Table\n\nImagine you have a SQL table called `hero` with:\n\n* `id`\n* `name`\n* `secret_name`\n* `age`\n\nAnd you want it to have this data:\n\n| id | name | secret_name | age |\n-----|------|-------------|------|\n| 1  | Deadpond | Dive Wilson | null |\n| 2  | Spider-Boy | Pedro Parqueador | null |\n| 3  | Rusty-Man | Tommy Sharp | 48 |\n\n### Create a SQLModel Model\n\nThen you could create a **SQLModel** model like this:\n\n```Python\nfrom sqlmodel import Field, SQLModel\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n```\n\nThat class `Hero` is a **SQLModel** model, the equivalent of a SQL table in Python code.\n\nAnd each of those class attributes is equivalent to each **table column**.\n\n### Create Rows\n\nThen you could **create each row** of the table as an **instance** of the model:\n\n```Python\nhero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\nhero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\nhero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n```\n\nThis way, you can use conventional Python code with **classes** and **instances** that represent **tables** and **rows**, and that way communicate with the **SQL database**.\n\n### Editor Support\n\nEverything is designed for you to get the best developer experience possible, with the best editor support.\n\nIncluding **autocompletion**:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/autocompletion01.png\">\n\nAnd **inline errors**:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/inline-errors01.png\">\n\n### Write to the Database\n\nYou can learn a lot more about **SQLModel** by quickly following the **tutorial**, but if you need a taste right now of how to put all that together and save to the database, you can do this:\n\n```Python hl_lines=\"16  19  21-25\"\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nhero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\nhero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\nhero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n\nengine = create_engine(\"sqlite:///database.db\")\n\n\nSQLModel.metadata.create_all(engine)\n\nwith Session(engine) as session:\n    session.add(hero_1)\n    session.add(hero_2)\n    session.add(hero_3)\n    session.commit()\n```\n\nThat will save a **SQLite** database with the 3 heroes.\n\n### Select from the Database\n\nThen you could write queries to select from that same database, for example with:\n\n```Python hl_lines=\"13-17\"\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nengine = create_engine(\"sqlite:///database.db\")\n\nwith Session(engine) as session:\n    statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n    hero = session.exec(statement).first()\n    print(hero)\n```\n\n### Editor Support Everywhere\n\n**SQLModel** was carefully designed to give you the best developer experience and editor support, **even after selecting data** from the database:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/autocompletion02.png\">\n\n## SQLAlchemy and Pydantic\n\nThat class `Hero` is a **SQLModel** model.\n\nBut at the same time, ✨ it is a **SQLAlchemy** model ✨. So, you can combine it and use it with other SQLAlchemy models, or you could easily migrate applications with SQLAlchemy to **SQLModel**.\n\nAnd at the same time, ✨ it is also a **Pydantic** model ✨. You can use inheritance with it to define all your **data models** while avoiding code duplication. That makes it very easy to use with **FastAPI**.\n\n## License\n\nThis project is licensed under the terms of the [MIT license](https://github.com/fastapi/sqlmodel/blob/main/LICENSE).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nSecurity is very important for SQLModel and its community. 🔒\n\nLearn more about it below. 👇\n\n## Versions\n\nThe latest versions of SQLModel are supported.\n\nYou are encouraged to [write tests](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/) for your application and update your SQLModel version frequently after ensuring that your tests are passing. This way you will benefit from the latest features, bug fixes, and **security fixes**.\n\n## Reporting a Vulnerability\n\nIf you think you found a vulnerability, and even if you are not sure about it, please report it right away by sending an email to: security@tiangolo.com. Please try to be as explicit as possible, describing all the steps and example code to reproduce the security issue.\n\nI (the author, [@tiangolo](https://twitter.com/tiangolo)) will review it thoroughly and get back to you.\n\n## Public Discussions\n\nPlease restrain from publicly discussing a potential security vulnerability. 🙊\n\nIt's better to discuss privately and try to find a solution first, to limit the potential impact as much as possible.\n\n---\n\nThanks for your help!\n\nThe SQLModel community and I thank you for that. 🙇\n"
  },
  {
    "path": "data/members.yml",
    "content": "members:\n- login: tiangolo\n- login: alejsdev\n"
  },
  {
    "path": "data/sponsors.yml",
    "content": "gold: []\nsilver:\n  - url: https://www.govcert.lu\n    title: This project is being supported by GOVCERT.LU\n    img: https://sqlmodel.tiangolo.com/img/sponsors/govcert.png\nbronze: []\n"
  },
  {
    "path": "docs/about/index.md",
    "content": "# About\n\nAbout **SQLModel**, its design, inspiration, and more. 🤓\n"
  },
  {
    "path": "docs/advanced/decimal.md",
    "content": "# Decimal Numbers\n\nIn some cases you might need to be able to store decimal numbers with guarantees about the precision.\n\nThis is particularly important if you are storing things like **currencies**, **prices**, **accounts**, and others, as you would want to know that you wouldn't have rounding errors.\n\nAs an example, if you open Python and sum `1.1` + `2.2` you would expect to see `3.3`, but you will actually get `3.3000000000000003`:\n\n```Python\n>>> 1.1 + 2.2\n3.3000000000000003\n```\n\nThis is because of the way numbers are stored in \"ones and zeros\" (binary). But Python has a module and some types to have strict decimal values. You can read more about it in the official <a href=\"https://docs.python.org/3/library/decimal.html\" class=\"external-link\" target=\"_blank\">Python docs for Decimal</a>.\n\nBecause databases store data in the same ways as computers (in binary), they would have the same types of issues. And because of that, they also have a special **decimal** type.\n\nIn most cases this would probably not be a problem, for example measuring views in a video, or the life bar in a videogame. But as you can imagine, this is particularly important when dealing with **money** and **finances**.\n\n## Decimal Types\n\nPydantic has special support for <a href=\"https://docs.pydantic.dev/latest/api/standard_library_types/#decimaldecimal\" class=\"external-link\" target=\"_blank\">`Decimal` types</a>.\n\nWhen you use `Decimal` you can specify the number of digits and decimal places to support in the `Field()` function. They will be validated by Pydantic (for example when using FastAPI) and the same information will also be used for the database columns.\n\n/// info\n\nFor the database, **SQLModel** will use <a href=\"https://docs.sqlalchemy.org/en/20/core/type_basics.html#sqlalchemy.types.DECIMAL\" class=\"external-link\" target=\"_blank\">SQLAlchemy's `DECIMAL` type</a>.\n\n///\n\n## Decimals in SQLModel\n\nLet's say that each hero in the database will have an amount of money. We could make that field a `Decimal` type using the `condecimal()` function:\n\n{* ./docs_src/advanced/decimal/tutorial001_py310.py ln[1:11] hl[11] *}\n\nHere we are saying that `money` can have at most `5` digits with `max_digits`, **this includes the integers** (to the left of the decimal dot) **and the decimals** (to the right of the decimal dot).\n\nWe are also saying that the number of decimal places (to the right of the decimal dot) is `3`, so we can have **3 decimal digits** for these numbers in the `money` field. This means that we will have **2 digits for the integer part** and **3 digits for the decimal part**.\n\n✅ So, for example, these are all valid numbers for the `money` field:\n\n* `12.345`\n* `12.3`\n* `12`\n* `1.2`\n* `0.123`\n* `0`\n\n🚫 But these are all invalid numbers for that `money` field:\n\n* `1.2345`\n  * This number has more than 3 decimal places.\n* `123.234`\n  * This number has more than 5 digits in total (integer and decimal part).\n* `123`\n  * Even though this number doesn't have any decimals, we still have 3 places saved for them, which means that we can **only use 2 places** for the **integer part**, and this number has 3 integer digits. So, the allowed number of integer digits is `max_digits` - `decimal_places` = 2.\n\n/// tip\n\nMake sure you adjust the number of digits and decimal places for your own needs, in your own application. 🤓\n\n///\n\n## Create models with Decimals\n\nWhen creating new models you can actually pass normal (`float`) numbers, Pydantic will automatically convert them to `Decimal` types, and **SQLModel** will store them as `Decimal` types in the database (using SQLAlchemy).\n\n{* ./docs_src/advanced/decimal/tutorial001_py310.py ln[24:34] hl[25:27] *}\n\n## Select Decimal data\n\nThen, when working with Decimal types, you can confirm that they indeed avoid those rounding errors from floats:\n\n{* ./docs_src/advanced/decimal/tutorial001_py310.py ln[37:50] hl[49:50] *}\n\n## Review the results\n\nNow if you run this, instead of printing the unexpected number `3.3000000000000003`, it prints `3.300`:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The type of money is Decimal('1.100')\nHero 1: id=1 secret_name='Dive Wilson' age=None name='Deadpond' money=Decimal('1.100')\n\n// More output omitted here 🤓\n\n// The type of money is Decimal('1.100')\nHero 2: id=3 secret_name='Tommy Sharp' age=48 name='Rusty-Man' money=Decimal('2.200')\n\n// No rounding errors, just 3.3! 🎉\nTotal money: 3.300\n```\n\n</div>\n\n/// warning\n\nAlthough Decimal types are supported and used in the Python side, not all databases support it. In particular, SQLite doesn't support decimals, so it will convert them to the same floating `NUMERIC` type it supports.\n\nBut decimals are supported by most of the other SQL databases. 🎉\n\n///\n"
  },
  {
    "path": "docs/advanced/index.md",
    "content": "# Advanced User Guide\n\nThe **Advanced User Guide** is gradually growing, you can already read about some advanced topics.\n\nAt some point it will include:\n\n* How to use `async` and `await` with the async session.\n* How to run migrations.\n* How to combine **SQLModel** models with SQLAlchemy.\n* ...and more. 🤓\n"
  },
  {
    "path": "docs/advanced/uuid.md",
    "content": "# UUID (Universally Unique Identifiers)\n\nWe have discussed some data types like `str`, `int`, etc.\n\nThere's another data type called `UUID` (Universally Unique Identifier).\n\nYou might have seen **UUIDs**, for example in URLs. They look something like this:\n\n```\n4ff2dab7-bffe-414d-88a5-1826b9fea8df\n```\n\nUUIDs can be particularly useful as an alternative to auto-incrementing integers for **primary keys**.\n\n/// info\n\nOfficial support for UUIDs was added in SQLModel version `0.0.20`.\n\n///\n\n## About UUIDs\n\nUUIDs are numbers with 128 bits, that is, 16 bytes.\n\nThey are normally seen as 32 <abbr title=\"numbers in base 16 (instead of base 10), using letters from A to F to represent the numbers from 10 to 15\">hexadecimal</abbr> characters separated by dashes.\n\nThere are several versions of UUID, some versions include the current time in the bytes, but **UUIDs version 4** are mainly random, the way they are generated makes them virtually **unique**.\n\n### Distributed UUIDs\n\nYou could generate one UUID in one computer, and someone else could generate another UUID in another computer, and it would be almost **impossible** for both UUIDs to be the **same**.\n\nThis means that you don't have to wait for the DB to generate the ID for you, you can **generate it in code before sending it to the database**, because you can be quite certain it will be unique.\n\n/// note | Technical Details\n\nBecause the number of possible UUIDs is so large (2^128), the probability of generating the same UUID version 4 (the random ones) twice is very low.\n\nIf you had 103 trillion version 4 UUIDs stored in the database, the probability of generating a duplicated new one is one in a billion. 🤓\n\n///\n\nFor the same reason, if you decided to migrate your database, combine it with another database and mix records, etc. you would most probably be able to **just use the same UUIDs** you had originally.\n\n/// warning\n\nThere's still a chance you could have a collision, but it's very low. In most cases you could assume you wouldn't have it, but it would be good to be prepared for it.\n\n///\n\n### UUIDs Prevent Information Leakage\n\nBecause UUIDs version 4 are **random**, you could give these IDs to the application users or to other systems, **without exposing information** about your application.\n\nWhen using **auto-incremented integers** for primary keys, you could implicitly expose information about your system. For example, someone could create a new hero, and by getting the hero ID `20` **they would know that you have 20 heroes** in your system (or even less, if some heroes were already deleted).\n\n### UUID Storage\n\nBecause UUIDs are 16 bytes, they would **consume more space** in the database than a smaller auto-incremented integer (commonly 4 bytes).\n\nDepending on the database you use, UUIDs could have **better or worse performance**. If you are concerned about that, you should check the documentation for the specific database.\n\nSQLite doesn't have a specific UUID type, so it will store the UUID as a string. Other databases like Postgres have a specific UUID type which would result in better performance and space usage than strings.\n\n## Models with UUIDs\n\nTo use UUIDs as primary keys we need to import `uuid`, which is part of the Python standard library (we don't have to install anything) and use `uuid.UUID` as the **type** for the ID field.\n\nWe also want the Python code to **generate a new UUID** when creating a new instance, so we use `default_factory`.\n\nThe parameter `default_factory` takes a function (or in general, a \"<abbr title=\"Something that can be called as a function.\">callable</abbr>\"). This function will be **called when creating a new instance** of the model and the value returned by the function will be used as the default value for the field.\n\nFor the function in `default_factory` we pass `uuid.uuid4`, which is a function that generates a **new UUID version 4**.\n\n/// tip\n\nWe don't call `uuid.uuid4()` ourselves in the code (we don't put the parenthesis). Instead, we pass the function itself, just `uuid.uuid4`, so that SQLModel can call it every time we create a new instance.\n\n///\n\nThis means that the UUID will be generated in the Python code, **before sending the data to the database**.\n\n{* ./docs_src/advanced/uuid/tutorial001_py310.py ln[1:10] hl[1,7] *}\n\nPydantic has support for <a href=\"https://docs.pydantic.dev/latest/api/standard_library_types/#uuid\" class=\"external-link\" target=\"_blank\">`UUID` types</a>.\n\nFor the database, **SQLModel** internally uses <a href=\"https://docs.sqlalchemy.org/en/20/core/type_basics.html#sqlalchemy.types.Uuid\" class=\"external-link\" target=\"_blank\">SQLAlchemy's `Uuid` type</a>.\n\n### Create a Record with a UUID\n\nWhen creating a `Hero` record, the `id` field will be **automatically populated** with a new UUID because we set `default_factory=uuid.uuid4`.\n\nAs `uuid.uuid4` will be called when creating the model instance, even before sending it to the database, we can **access and use the ID right away**.\n\nAnd that **same ID (a UUID)** will be saved in the database.\n\n{* ./docs_src/advanced/uuid/tutorial001_py310.py ln[23:34] hl[25,27,29,34] *}\n\n### Select a Hero\n\nWe can do the same operations we could do with other fields.\n\nFor example we can **select a hero by ID**:\n\n{* ./docs_src/advanced/uuid/tutorial001_py310.py ln[37:54] hl[49] *}\n\n/// tip\n\nEven if a database like SQLite stores the UUID as a string, we can select and run comparisons using a Python UUID object and it will work.\n\nSQLModel (actually SQLAlchemy) will take care of making it work. ✨\n\n///\n\n#### Select with `session.get()`\n\nWe could also select by ID with `session.get()`:\n\n{* ./docs_src/advanced/uuid/tutorial002_py310.py ln[37:53] hl[49] *}\n\nThe same way as with other fields, we could update, delete, etc. 🚀\n\n### Run the program\n\nIf you run the program, you will see the **UUID** generated in the Python code, and then the record **saved in the database with the same UUID**.\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// In SQLite, the UUID will be stored as a string\n// other DBs like Postgres have a specific UUID type\nCREATE TABLE hero (\n        id CHAR(32) NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        PRIMARY KEY (id)\n)\n\n// Before saving in the DB we already have the UUID\nThe hero before saving in the DB\nname='Deadpond' secret_name='Dive Wilson' id=UUID('0e44c1a6-88d3-4a35-8b8a-307faa2def28') age=None\nThe hero ID was already set\n0e44c1a6-88d3-4a35-8b8a-307faa2def28\n\n// The SQL statement to insert the record uses our UUID\nINSERT INTO hero (id, name, secret_name, age) VALUES (?, ?, ?, ?)\n('0e44c1a688d34a358b8a307faa2def28', 'Deadpond', 'Dive Wilson', None)\n\n// And indeed, the record was saved with the UUID we created 😎\nAfter saving in the DB\nage=None id=UUID('0e44c1a6-88d3-4a35-8b8a-307faa2def28') name='Deadpond' secret_name='Dive Wilson'\n\n// Now we create a new hero (to select it in a bit)\nCreated hero:\nage=None id=UUID('9d90d186-85db-4eaa-891a-def7b4ae2dab') name='Spider-Boy' secret_name='Pedro Parqueador'\nCreated hero ID:\n9d90d186-85db-4eaa-891a-def7b4ae2dab\n\n// And now we select it\nSelected hero:\nage=None id=UUID('9d90d186-85db-4eaa-891a-def7b4ae2dab') name='Spider-Boy' secret_name='Pedro Parqueador'\nSelected hero ID:\n9d90d186-85db-4eaa-891a-def7b4ae2dab\n```\n\n</div>\n\n## Learn More\n\nYou can learn more about **UUIDs** in:\n\n* The official <a href=\"https://docs.python.org/3/library/uuid.html\" class=\"external-link\" target=\"_blank\">Python docs for UUID</a>.\n* The <a href=\"https://en.wikipedia.org/wiki/Universally_unique_identifier\" class=\"external-link\" target=\"_blank\">Wikipedia for UUID</a>.\n"
  },
  {
    "path": "docs/alternatives.md",
    "content": "# Alternatives, Inspiration and Comparisons\n\nComing soon...\n"
  },
  {
    "path": "docs/contributing.md",
    "content": "# Contributing\n\nFirst, you might want to see the basic ways to [help SQLModel and get help](help.md){.internal-link target=_blank}.\n\n## Developing\n\nIf you already cloned the <a href=\"https://github.com/fastapi/sqlmodel\" class=\"external-link\" target=\"_blank\">sqlmodel repository</a> and you want to deep dive in the code, here are some guidelines to set up your environment.\n\n### Install Requirements Using `uv`\n\nCreate a virtual environment and install the required packages in one command:\n\n<div class=\"termy\">\n\n```console\n$ uv sync\n\n---> 100%\n```\n\n</div>\n\nIt will install all the dependencies and your local SQLModel in your local environment.\n\n### Using your Local SQLModel\n\nIf you create a Python file that imports and uses SQLModel, and run it with the Python from your local environment, it will use your cloned local SQLModel source code.\n\nAnd if you update that local SQLModel source code when you run that Python file again, it will use the fresh version of SQLModel you just edited.\n\nThat way, you don't have to \"install\" your local version to be able to test every change.\n\n/// note | \"Technical Details\"\n\nThis only happens when you install using this included `requirements.txt` instead of running `pip install sqlmodel` directly.\n\nThat is because inside the `requirements.txt` file, the local version of SQLModel is marked to be installed in \"editable\" mode, with the `-e` option.\n\n///\n\n### Format\n\nThere is a script that you can run that will format and clean all your code:\n\n<div class=\"termy\">\n\n```console\n$ bash scripts/format.sh\n```\n\n</div>\n\nIt will also auto-sort all your imports.\n\n## Tests\n\nThere is a script that you can run locally to test all the code and generate coverage reports in HTML:\n\n<div class=\"termy\">\n\n```console\n$ bash scripts/test.sh\n```\n\n</div>\n\nThis command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing.\n\n## Docs\n\nFirst, make sure you set up your environment as described above, that will install all the requirements.\n\n### Docs Live\n\nDuring local development, there is a script that builds the site and checks for any changes, live-reloading:\n\n<div class=\"termy\">\n\n```console\n$ python ./scripts/docs.py live\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\n</div>\n\nIt will serve the documentation on `http://127.0.0.1:8008`.\n\nThat way, you can edit the documentation/source files and see the changes live.\n\n/// tip\n\nAlternatively, you can perform the same steps that scripts does manually.\n\nGo into the docs director at `docs/`:\n\n```console\n$ cd docs/\n```\n\nThen run `mkdocs` in that directory:\n\n```console\n$ mkdocs serve --dev-addr 8008\n```\n\n///\n\n#### Typer CLI (Optional)\n\nThe instructions here show you how to use the script at `./scripts/docs.py` with the `python` program directly.\n\nBut you can also use <a href=\"https://typer.tiangolo.com/typer-cli/\" class=\"external-link\" target=\"_blank\">Typer CLI</a>, and you will get autocompletion in your terminal for the commands after installing completion.\n\nIf you install Typer CLI, you can install completion with:\n\n<div class=\"termy\">\n\n```console\n$ typer --install-completion\n\nzsh completion installed in /home/user/.bashrc.\nCompletion will take effect once you restart the terminal.\n```\n\n</div>\n\n### Docs Structure\n\nThe documentation uses <a href=\"https://www.mkdocs.org/\" class=\"external-link\" target=\"_blank\">MkDocs</a>.\n\nAnd there are extra tools/scripts in place in `./scripts/docs.py`.\n\n/// tip\n\nYou don't need to see the code in `./scripts/docs.py`, you just use it in the command line.\n\n///\n\nAll the documentation is in Markdown format in the directory `./docs`.\n\nMany of the tutorials have blocks of code.\n\nIn most of the cases, these blocks of code are actual complete applications that can be run as is.\n\nIn fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs_src/` directory.\n\nAnd those Python files are included/injected in the documentation when generating the site.\n\n### Docs for Tests\n\nMost of the tests actually run against the example source files in the documentation.\n\nThis helps to make sure that:\n\n* The documentation is up-to-date.\n* The documentation examples can be run as is.\n* Most of the features are covered by the documentation, ensured by test coverage.\n\n## Automated Code and AI\n\nYou are encouraged to use all the tools you want to do your work and contribute as efficiently as possible, this includes AI (LLM) tools, etc. Nevertheless, contributions should have meaningful human intervention, judgement, context, etc.\n\nIf the **human effort** put in a PR, e.g. writing LLM prompts, is **less** than the **effort we would need to put** to **review it**, please **don't** submit the PR.\n\nThink of it this way: we can already write LLM prompts or run automated tools ourselves, and that would be faster than reviewing external PRs.\n\n### Closing Automated and AI PRs\n\nIf we see PRs that seem AI generated or automated in similar ways, we'll flag them and close them.\n\nThe same applies to comments and descriptions, please don't copy paste the content generated by an LLM.\n\n### Human Effort Denial of Service\n\nUsing automated tools and AI to submit PRs or comments that we have to carefully review and handle would be the equivalent of a <a href=\"https://en.wikipedia.org/wiki/Denial-of-service_attack\" class=\"external-link\" target=\"_blank\">Denial-of-service attack</a> on our human effort.\n\nIt would be very little effort from the person submitting the PR (an LLM prompt) that generates a large amount of effort on our side (carefully reviewing code).\n\nPlease don't do that.\n\nWe'll need to block accounts that spam us with repeated automated PRs or comments.\n\n### Use Tools Wisely\n\nAs Uncle Ben said:\n\n<blockquote>\nWith great <strike>power</strike> <strong>tools</strong> comes great responsibility.\n</blockquote>\n\nAvoid inadvertently doing harm.\n\nYou have amazing tools at hand, use them wisely to help effectively.\n"
  },
  {
    "path": "docs/css/custom.css",
    "content": "/* Fira Code, including characters used by Rich output, like the \"heavy right-pointing angle bracket ornament\", not included in Google Fonts */\n@import url(https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css);\n/* Noto Color Emoji for emoji support with the same font everywhere */\n@import url(https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap);\n\n/* Override default code font in Material for MkDocs to Fira Code */\n:root {\n    --md-code-font: \"Fira Code\", monospace, \"Noto Color Emoji\";\n}\n\n/* Override default regular font in Material for MkDocs to include Noto Color Emoji */\n:root {\n    --md-text-font: \"Roboto\", \"Noto Color Emoji\";\n}\n\n.termynal-comment {\n    color: #4a968f;\n    font-style: italic;\n    display: block;\n}\n\n.termy [data-termynal] {\n    white-space: pre-wrap;\n}\n\n.termy .linenos {\n    display: none;\n}\n\n/* External links: detected by JS comparing origin to site origin\n   JS sets data-external-link on links pointing outside the site\n   Skip image links, .no-link-icon, and .announce-link */\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link) {\n  /* For right to left languages */\n  direction: ltr;\n  display: inline-block;\n}\n\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link)::after {\n  content: \"\";\n  display: inline-block;\n  width: 0.75em;\n  height: 0.75em;\n  margin-left: 0.25em;\n  vertical-align: middle;\n  opacity: 0.55;\n  background: currentColor;\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E\");\n  -webkit-mask-size: contain;\n  -webkit-mask-repeat: no-repeat;\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E\");\n  mask-size: contain;\n  mask-repeat: no-repeat;\n}\n\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link):hover::after {\n  opacity: 0.85;\n}\n\n/* Internal links opening in new tab: same-origin links with target=_blank\n   JS sets data-internal-link on links pointing to the same site origin\n   Skip image links, .no-link-icon, and .announce-link */\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link) {\n  /* For right to left languages */\n  direction: ltr;\n  display: inline-block;\n}\n\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link)::after {\n  content: \"\";\n  display: inline-block;\n  width: 0.75em;\n  height: 0.75em;\n  margin-left: 0.25em;\n  vertical-align: middle;\n  opacity: 0.55;\n  background: currentColor;\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='7' width='14' height='14' rx='2'/%3E%3Cpath d='M7 3h14v14'/%3E%3C/svg%3E\");\n  -webkit-mask-size: contain;\n  -webkit-mask-repeat: no-repeat;\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='7' width='14' height='14' rx='2'/%3E%3Cpath d='M7 3h14v14'/%3E%3C/svg%3E\");\n  mask-size: contain;\n  mask-repeat: no-repeat;\n}\n\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link):hover::after {\n  opacity: 0.85;\n}\n\n/* Disable link icons in footer and header nav */\n.md-footer a::after,\n.md-header a::after {\n  content: none !important;\n}\n\n.shadow {\n    box-shadow: 5px 5px 10px #999;\n}\n\n.user-list {\n    display: flex;\n    flex-wrap: wrap;\n    margin-bottom: 2rem;\n}\n\n.user-list-center {\n    justify-content: space-evenly;\n}\n\n.user {\n    margin: 1em;\n    min-width: 7em;\n}\n\n.user .avatar-wrapper {\n    width: 80px;\n    height: 80px;\n    margin: 10px auto;\n    overflow: hidden;\n    border-radius: 50%;\n    position: relative;\n}\n\n.user .avatar-wrapper img {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n}\n\n.user .title {\n    text-align: center;\n}\n\n.user .count {\n    font-size: 80%;\n    text-align: center;\n}\n"
  },
  {
    "path": "docs/css/termynal.css",
    "content": "/**\n * termynal.js\n *\n * @author Ines Montani <ines@ines.io>\n * @version 0.0.1\n * @license MIT\n */\n\n:root {\n    --color-bg: #252a33;\n    --color-text: #eee;\n    --color-text-subtle: #a2a2a2;\n}\n\n[data-termynal] {\n    width: 750px;\n    max-width: 100%;\n    background: var(--color-bg);\n    color: var(--color-text);\n    /* font-size: 18px; */\n    font-size: 15px;\n    /* font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; */\n    font-family: var(--md-code-font-family), 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;\n    border-radius: 4px;\n    padding: 75px 45px 35px;\n    position: relative;\n    -webkit-box-sizing: border-box;\n            box-sizing: border-box;\n    /* Custom line-height */\n    line-height: 1.2;\n}\n\n[data-termynal]:before {\n    content: '';\n    position: absolute;\n    top: 15px;\n    left: 15px;\n    display: inline-block;\n    width: 15px;\n    height: 15px;\n    border-radius: 50%;\n    /* A little hack to display the window buttons in one pseudo element. */\n    background: #d9515d;\n    -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n            box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n}\n\n[data-termynal]:after {\n    content: 'bash';\n    position: absolute;\n    color: var(--color-text-subtle);\n    top: 5px;\n    left: 0;\n    width: 100%;\n    text-align: center;\n}\n\na[data-terminal-control] {\n    text-align: right;\n    display: block;\n    color: #aebbff;\n}\n\n[data-ty] {\n    display: block;\n    line-height: 2;\n}\n\n[data-ty]:before {\n    /* Set up defaults and ensure empty lines are displayed. */\n    content: '';\n    display: inline-block;\n    vertical-align: middle;\n}\n\n[data-ty=\"input\"]:before,\n[data-ty-prompt]:before {\n    margin-right: 0.75em;\n    color: var(--color-text-subtle);\n}\n\n[data-ty=\"input\"]:before {\n    content: '$';\n}\n\n[data-ty][data-ty-prompt]:before {\n    content: attr(data-ty-prompt);\n}\n\n[data-ty-cursor]:after {\n    content: attr(data-ty-cursor);\n    font-family: monospace;\n    margin-left: 0.5em;\n    -webkit-animation: blink 1s infinite;\n            animation: blink 1s infinite;\n}\n\n\n/* Cursor animation */\n\n@-webkit-keyframes blink {\n    50% {\n        opacity: 0;\n    }\n}\n\n@keyframes blink {\n    50% {\n        opacity: 0;\n    }\n}\n"
  },
  {
    "path": "docs/databases.md",
    "content": "# Intro to Databases\n\n/// info\n\nAre you a seasoned developer and already know everything about databases? 🤓\n\nThen you can skip to the next sections right away.\n\n///\n\nIf you don't know everything about databases, here's a quick overview.\n\nYou can always study much more on your own later.\n\nBut this should help you start using databases and being productive with **SQLModel**. 🚀\n\n## What is a Database\n\nSo, what is a database?\n\nA **database** is a system to store and manage data in a structured and very efficient way.\n\n/// tip\n\nIt's very common to abbreviate the word \"database\" as **\"DB\"**.\n\n///\n\nAs there's a lot of information about databases, and it can get very technical and academic, I'll give you a quick overview about some of the main concepts here.\n\nI'll even tell you a bit about different types of databases, including the ones not covered by SQLModel (\"NoSQL\" databases).\n\n## Why Use a Database\n\nWhen starting to program, it might **not be obvious** why having a database apart from the code for your program is a **good idea**. Let's start with that.\n\n/// tip\n\nIf that's obvious to you, just continue in the next section below. 👇\n\n///\n\nIn your code you already have **variables**, **dictionaries**, **lists**, etc. They all store **data** in some way already. Why would you need to have a separate database?\n\nIf you look closely, your code is **static**, it doesn't really change over time *once you run it*. Of course, you change the code frequently, adding features, etc, but once you start Python running your code, the program stays as it was when you started it. And if you change the code, the program will only change **once you run it again**.\n\nAnd even if you change things in variables, once the program terminates, all that data that was in **memory** is **gone**. 🔥\n\nIn most of the cases, the objective of your program is to do something with data *outside* of the program.\n\n* It could be just moving **files** from one place to the other.\n* Or it could be taking data from the user in the **terminal** and showing it differently.\n* Or a **web API** that takes some data and process it in some way, etc.\n\nIn most cases, the data *comes from outside* the program or *ends outside the program* (for example, shown on the screen, in a file, etc).\n\nIn many cases, you need your program to be able to **create** and store data, **read** it, **update** it, **delete** it, etc.\n\nYou could do all that by reading and writing to files from your code. And that works in simple cases. But for most complex systems with data that is a bit more **complex** that strategy is not very efficient. And you would have to deal with a lot of **caveats**, keeping the data in sync, making sure it is safely stored, etc.\n\nDatabases are designed to **solve these problems**, making the process of handling data much more efficient, and independent of your code. ✨\n\n## How to Interact with a Database\n\nThere are many databases of many types.\n\n### A single file database\n\nA database could be a single file called `heroes.db`, managed with code in a very efficient way. An example would be SQLite, more about that in a bit.\n\n![database as a single file](img/databases/single-file.drawio.svg)\n\n### A server database\n\nA database could also be a system running as an application on a server, handling multiple files internally in optimized formats.\n\nLike a web server, but communicating in a custom and very efficient way. That is the most common type of database interaction.\n\nIn this case, your code would talk to this server application instead of reading or modifying files directly.\n\nThe database could be located in a different server/machine:\n\n![database in an external server](img/databases/external-server.drawio.svg)\n\nOr the database could be located in the same server/machine:\n\n![database in the same server](img/databases/same-server.drawio.svg)\n\nThe most important aspect of these types of databases is that **your code doesn't read or modify** the files containing the data directly.\n\nInstead, your code communicates with the database application and that database application is the one that actually reads and modifies its data files. This is because this database application is normally **much more efficient** than what your code could be.\n\nSome examples of databases that work like this could be **PostgreSQL**, **MySQL**, or **MongoDB**.\n\n### Distributed servers\n\nIn some cases, the database could even be a group of server applications running on different machines, working together and communicating between them to be more efficient and handle more data.\n\nIn this case, your code would talk to one or more of these server applications running on different machines.\n\n![distributed database in multiple servers](img/databases/multiple-servers.drawio.svg)\n\nMost of the databases that work as server applications also support multiple servers in one way or another.\n\nHaving distributed systems also creates additional challenges, so there's a high chance that you would first interact with a single server application or one based on a single file.\n\n## SQL Databases\n\nWe already talked about the different ways to interact with a database and how they handle files, etc. That applies to most or all of the databases.\n\nBut there's another way to categorize databases that is very important. As you can imagine, there are many types of databases and many databases in each group. But in general, they can be separated in two big groups: \"SQL Databases\" and \"NoSQL Databases\".\n\nWe will get to why the name \"SQL\" in a bit, but first, let's see what is it all about.\n\n### SQLModel for SQL Databases\n\n**SQLModel** is a tool to help you with **SQL Databases**.\n\nIt cannot help you much with **NoSQL Databases**. Nevertheless, I'll explain a bit about them here.\n\n## Invent SQL Databases\n\nA long time ago, some smart people realized that a great way to store data was putting it in different tables.\n\nAnd by \"table\" I mean just data in a grid, with different columns and rows, pretty much like a single spreadsheet.\n\nEach row would represent a specific item or **record**. And each column would represent a specific attribute or field of that record.\n\n### An example of a big table\n\nLet's imagine that we need to store some data about heroes.\n\nIf we worked with a single table to store our heroes, it could be like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>Z-Factor</td><td>Sister Margaret's Bar</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n</table>\n\nThat's probably what we would have to do with a single table, for example, with a single spreadsheet.\n\nBut there are some problems with this. Let's check some.\n\n#### Single table problems\n\nImagine that they decided to rename the \"Sharp Tower\" to \"Preventers Tower\".\n\nNow we would have to update that in two places.\n\nWhat happens if our code starts to update that name in one place and suddenly there's a power outage and the computer goes off?\n\nWe could end up with inconsistent information, having one place saying \"Preventers Tower\" and the other one saying \"Sharp Tower\":\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>Preventers</td><td>Preventers Tower ✅</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>Preventers</td><td>Sharp Tower 🚨</td>\n</tr>\n</table>\n\nAnd now imagine that we need to add a new hero called \"Mahjong\" that is part of the team \"Z-Force\".\n\nWe could forget the name of the team and end up adding \"Mahjong\" with an invalid team name, for example \"Y-Force\".\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>Preventers</td><td>Preventers Tower</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>4</td><td>Mahjong</td><td>Neena Thurgirl</td><td>31</td><td>Y-Force 🚨</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd what if a single hero belongs to two teams? We wouldn't have an easy way to put this into a single big table.\n\n### Multiple tables\n\nBut these and other problems could be solved better by having the data in multiple tables.\n\nSo, instead of having a single table with all the data, we could have one table for the heroes and one for teams, and a way to connect one with the other.\n\nThe table for the teams could look like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nNow, the table for the heroes would look almost the same. But remember that we mentioned that we need a way to connect the two tables?\n\nThe table for the heroes would now have another column `team_id`. This column shows the relationship from each row (from each hero) to the team they belong to.\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id ✨</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2 ✨</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1 ✨</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1 ✨</td>\n</tr>\n</table>\n\n#### Identifications - Primary Key\n\nIn the example above, each one of the rows has an <abbr title='abbreviated from the word \"identification\", in many cases written as \"ID\"'>`id`</abbr>. Each ID is unique per table and identifies that particular row.\n\nThese SQL databases require having a unique way to identify each row in a table. It could be a combination of columns that is unique, but commonly it is just one single column. This is called the \"**primary key**\" of the table.\n\nThe **primary key** is frequently a single column, commonly it's just an integer generated automatically by the database, and in many cases, the column is simply called `id`.\n\nThis **primary key**, in this case the column `id`, has to be unique per table. But two different tables could have the same ID. For example, above, both tables have the ID `2` for two different rows, one for \"**Z-Force**\" in one table and one for \"**Spider-Boy**\" in the other table, but that's still okay as long as there's a single one per table.\n\n#### Relationships - Foreign Key\n\nEach row in a table has a single **primary key** (in our example a single column `id`).\n\nFor example, the table for the teams has the ID `1` for the team `Preventers` and the ID `2` for the team `Z-Force`.\n\nAs these **primary key** IDs can uniquely identify each row on the table for teams, we can now go to the table for heroes and refer to those IDs in the table for teams.\n\n![table relationships](img/databases/relationships.drawio.svg)\n\nSo, in the table for heroes, we use the `team_id` column to define a relationship to the *foreign* table for teams. Each value in the `team_id` column on the table with heroes will be the same value as the `id` column of one row in the table with teams.\n\nIn the table for heroes we have a **primary key** that is the `id`. But we also have another column `team_id` that refers to a **key** in a **foreign** table. There's a technical term for that too, the `team_id` is a \"**foreign key**\".\n\n### Relations and Relational Databases\n\nThe technical and academic term for each one of these tables is a \"**relation**\".\n\nYou might hear that term a lot when talking about these databases.\n\nIt doesn't have the meaning that you would use in English of something being related to something else, even though each of these tables is actually \"related\" to the others.\n\nThe technical term **relation** just refers to each one of these tables.\n\nAnd because of this technical term, these **SQL Databases** are also called **Relational Databases** (in fact, that is the technically correct term). But it still just refers to these databases made with multiple tables.\n\n### SQL - The Language\n\nAfter developing these ideas of how to store data in multiple tables they also created a **language** that could be used to interact with them.\n\nThe language is called **SQL**, the name comes from for **Structured Query Language**.\n\nNevertheless, the language is not only used to *query* for data. It is also used to create records/rows, to update them, to delete them. And to manipulate the database, create tables, etc.\n\nThis language is supported by all these databases that handle multiple tables, that's why they are called **SQL Databases**. Although, each database has small variations in the SQL language they support (*dialect*).\n\nLet's imagine that the table holding the heroes is called the `hero` table. An example of a SQL query to get all the data from it could look like:\n\n```SQL\nSELECT *\nFROM hero;\n```\n\nAnd that SQL query would return the table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n</table>\n\n### SQLModel for SQL\n\n**SQLModel** is a library that helps you write Python code with regular Python objects, and then it transfers that to **SQL** statements that it sends to a **SQL Database**.\n\nNext, it receives the data and puts it in Python objects that you can continue to use in your code.\n\nI'll tell you more about SQL, SQLModel, how to use them, and how they are related in the next sections.\n\n/// info  | Technical Details\n\nSQLModel is built on top of SQLAlchemy. It is, in fact, just <a href=\"https://www.sqlalchemy.org/\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a> and <a href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\">Pydantic</a> mixed together with some sugar on top.\n\n///\n\n## NoSQL Databases\n\nAlthough SQL Databases are the oldest and most commonly used type of database, there's another (very interesting) category, the one of **NoSQL Databases**.\n\n**NoSQL Databases** covers a wide range of different sub-types, including key-value stores, document stores, graph databases, and more.\n\n**SQLModel** can only help you with SQL Databases. So, that's what we'll talk about in the rest of the documentation.\n"
  },
  {
    "path": "docs/db-to-code.md",
    "content": "# Database to Code (ORMs)\n\nHere I'll tell you how **SQLModel** interacts with the database, why you would want to use it (or use a similar tool), and how it relates to SQL.\n\n## SQL Inline in Code\n\nLet's check this example of a simple SQL query to get all the data from the `hero` table:\n\n```SQL\nSELECT *\nFROM hero;\n```\n\nAnd that SQL query would return the table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n</table>\n\nThis SQL language has a little **caveat**. It was not designed to be mixed with normal code in a programming language like Python. 🚨\n\nSo, if you are working with Python, the simplest option would be to put SQL code inside a string, and send that string directly to the database.\n\n```Python\nstatement = \"SELECT * FROM hero;\"\n\nresults = database.execute(statement)\n```\n\nBut in that case, you wouldn't have editor support, inline errors, autocompletion, etc. Because for the editor, the SQL statement is just a string of text. If you have an error, the editor wouldn't be able to help. 😔\n\nAnd even more importantly, in most of the cases, you would send the SQL strings with modifications and parameters. For example, to get the data for a *specific item ID*, a *range of dates*, etc.\n\nAnd in most cases, the parameters your code uses to query or modify the data in the database come, in some way, from an external user.\n\nFor example, check this SQL query:\n\n```SQL\nSELECT *\nFROM hero\nWHERE id = 2;\n```\n\nIt is using the ID parameter `2`. That number `2` probably comes, in some way, from a user input.\n\nThe user is probably, in some way, telling your application:\n\n> Hey, I want to get the hero with ID:\n\n```SQL\n2\n```\n\nAnd the result would be this table (with a single row):\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n</table>\n\n### SQL Injection\n\nBut let's say that your code takes whatever the external user provides and puts it inside the SQL string before sending it to the database. Something like this:\n\n```Python\n# Never do this! 🚨 Continue reading.\n\nuser_id = input(\"Type the user ID: \")\n\nstatement = f\"SELECT * FROM hero WHERE id = {user_id};\"\n\nresults = database.execute(statement)\n```\n\nIf the external user is actually an attacker, they could send you a malicious SQL string that does something terrible like deleting all the records. That's called a \"**SQL Injection**\".\n\nFor example, imagine that this new attacker user says:\n\n> Hey, I want to get the hero with ID:\n\n```SQL\n2; DROP TABLE hero\n```\n\nThen the code above that takes the user input and puts it in SQL would actually send this to the database:\n\n```SQL\nSELECT * FROM hero WHERE id = 2; DROP TABLE hero;\n```\n\nCheck that section added at the end. That's another entire SQL statement:\n\n```SQL\nDROP TABLE hero;\n```\n\nThat is how you tell the database in SQL to delete the entire table `hero`.\n\n<a href=\"https://theuselessweb.site/nooooooooooooooo/\" class=\"external-link\" target=\"_blank\">Nooooo!</a> We lost all the data in the `hero` table! 💥😱\n\n### SQL Sanitization\n\nThe process of making sure that whatever the external user sends is safe to use in the SQL string is called **sanitization**.\n\nIt comes by default in **SQLModel** (thanks to SQLAlchemy). And many other similar tools would also provide that functionality among many other features.\n\nNow you are ready for <a href=\"https://xkcd.com/327/\" class=\"external-link\" target=\"_blank\">a  joke from xkcd</a>:\n\n![Exploits of a Mom](https://imgs.xkcd.com/comics/exploits_of_a_mom.png)\n\n## SQL with SQLModel\n\nWith **SQLModel**, instead of writing SQL statements directly, you use Python classes and objects to interact with the database.\n\nFor example, you could ask the database for the same hero with ID `2` with this code:\n\n```Python\nuser_id = input(\"Type the user ID: \")\n\nsession.exec(\n    select(Hero).where(Hero.id == user_id)\n).all()\n```\n\nIf the user provides this ID:\n\n```SQL\n2\n```\n\n...the result would be this table (with a single row):\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n</table>\n\n### Preventing SQL Injections\n\nIf the user is an attacker and tries to send this as the \"ID\":\n\n```SQL\n2; DROP TABLE hero\n```\n\nThen **SQLModel** will convert that to a literal string `\"2; DROP TABLE hero\"`.\n\nAnd then, it will tell the SQL Database to try to find a record with that exact ID instead of injecting the attack.\n\nThe difference in the final SQL statement is subtle, but it changes the meaning completely:\n\n```SQL\nSELECT * FROM hero WHERE id = \"2; DROP TABLE hero;\";\n```\n\n/// tip\n\nNotice the double quotes (`\"`) making it a string instead of more raw SQL.\n\n///\n\nThe database will not find any record with that ID:\n\n```SQL\n\"2; DROP TABLE hero;\"\n```\n\nThen the database will send an empty table as the result because it didn't find any record with that ID.\n\nThen your code will continue to execute and calmly tell the user that it couldn't find anything.\n\nBut we never deleted the `hero` table. 🎉\n\n/// info\n\nOf course, there are also other ways to do SQL data sanitization without using a tool like **SQLModel**, but it's still a nice feature you get by default.\n\n///\n\n### Editor Support\n\nCheck that Python snippet above again.\n\nBecause we are using **standard Python classes and objects**, your editor will be able to provide you with autocompletion, inline errors, etc.\n\nFor example, let's say you wanted to query the database to find a hero based on the secret identity.\n\nMaybe you don't remember how you named the column. Maybe it was:\n\n* `secret_identity`?\n\n...or was it:\n\n* `secretidentity`?\n\n...or:\n\n* `private_name`?\n* `secret_name`?\n* `secretname`?\n\nIf you type that in SQL strings in your code, your editor **won't be able to help you**:\n\n```SQL\nstatement = \"SELECT * FROM hero WHERE secret_identity = 'Dive Wilson';\"\n\nresults = database.execute(statement)\n```\n\n...your editor will see that as a **long string** with some text inside, and it will **not be able to autocomplete** or detect the error in `secret_identity`.\n\nBut if you use common Python classes and objects, your editor will be able to help you:\n\n```Python\ndatabase.execute(\n    select(Hero).where(Hero.secret_name == \"Dive Wilson\")\n).all()\n```\n\n![](img/db-to-code/autocompletion01.png){class=\"shadow\"}\n\n## ORMs and SQL\n\nThese types of libraries like **SQLModel** (and of course, SQLAlchemy) that translate between SQL and code with classes and objects are called **ORMs**.\n\n**ORM** means **Object-Relational Mapper**.\n\nThis is a very common term, but it also comes from quite technical and **academical** concepts 👩‍🎓:\n\n* **Object**: refers to code with classes and instances, normally called \"Object Oriented Programming\", that's why the \"**Object**\" part.\n\nFor example this class is part of that **Object** Oriented Programming:\n\n```Python\nclass Hero(SQLModel):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n```\n\n* **Relational**: refers to the **SQL Databases**. Remember that they are also called **Relational Databases**, because each of those tables is also called a \"**relation**\"? That's where the \"**Relational**\" comes from.\n\nFor example this **Relation** or table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n</table>\n\n* **Mapper**: this comes from Math, when there's something that can convert from some set of things to another, that's called a \"**mapping function**\". That's where the **Mapper** comes from.\n\n![Squares to Triangles Mapper](img/db-to-code/mapper.drawio.svg)\n\nWe could also write a **mapping function** in Python that converts from the *set of lowercase letters* to the *set of uppercase letters*, like this:\n\n```Python\ndef map_lower_to_upper(value: str):\n    return value.upper()\n```\n\nIt's actually a simple idea with a very academic and mathematical name. 😅\n\nSo, an **ORM** is a library that translates from SQL to code, and from code to SQL. All using classes and objects.\n\nThere are many ORMs available apart from **SQLModel**, you can read more about some of them in [Alternatives, Inspiration and Comparisons](alternatives.md){.internal-link target=_blank}\n\n## SQL Table Names\n\n/// info  | Technical Background\n\nThis is a bit of boring background for SQL purists. Feel free to skip this section. 😉\n\n///\n\nWhen working with pure SQL, it's common to name the tables in plural. So, the table would be named `heroes` instead of `hero`, because it could contain multiple rows, each with one hero.\n\nNevertheless, **SQLModel** and many other similar tools can generate a table name automatically from your code, as you will see later in the tutorial.\n\nBut this name will be derived from a class name. And it's common practice to use **singular** names for classes (e.g. `class Hero`, instead of `class Heroes`). Using singular names for classes like `class Hero` also makes your code more intuitive.\n\nYou will see **your own code** a lot more than the internal table names, so it's probably better to keep the code/class convention than the SQL convention.\n\nSo, to keep things consistent, I'll keep using the same table names that **SQLModel** would have generated.\n\n/// tip\n\nYou can also override the table name. You can read about it in the Advanced User Guide.\n\n///\n"
  },
  {
    "path": "docs/environment-variables.md",
    "content": "# Environment Variables\n\nBefore we jump into code, let's cover a bit some of the **basics** that we'll need to understand how to work with Python (and programming) in general. Let's check a bit about **environment variables**.\n\n/// tip\n\nIf you already know what \"environment variables\" are and how to use them, feel free to skip this.\n\n///\n\nAn environment variable (also known as \"**env var**\") is a variable that lives **outside** of the Python code, in the **operating system**, and could be read by your Python code (or by other programs as well).\n\nEnvironment variables could be useful for handling application **settings**, as part of the **installation** of Python, etc.\n\n## Create and Use Env Vars\n\nYou can **create** and use environment variables in the **shell (terminal)**, without needing Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// You could create an env var MY_NAME with\n$ export MY_NAME=\"Wade Wilson\"\n\n// Then you could use it with other programs, like\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Use it with other programs, like\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Read env vars in Python\n\nYou could also create environment variables **outside** of Python, in the terminal (or with any other method), and then **read them in Python**.\n\nFor example you could have a file `main.py` with:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip\n\nThe second argument to <a href=\"https://docs.python.org/3.8/library/os.html#os.getenv\" class=\"external-link\" target=\"_blank\">`os.getenv()`</a> is the default value to return.\n\nIf not provided, it's `None` by default, here we provide `\"World\"` as the default value to use.\n\n///\n\nThen you could call that Python program:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ export MY_NAME=\"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nAs environment variables can be set outside of the code, but can be read by the code, and don't have to be stored (committed to `git`) with the rest of the files, it's common to use them for configurations or **settings**.\n\nYou can also create an environment variable only for a **specific program invocation**, that is only available to that program, and only for its duration.\n\nTo do that, create it right before the program itself, on the same line:\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME in line for this program call\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n\n// The env var no longer exists afterwards\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip\n\nYou can read more about it at <a href=\"https://12factor.net/config\" class=\"external-link\" target=\"_blank\">The Twelve-Factor App: Config</a>.\n\n///\n\n## Types and Validation\n\nThese environment variables can only handle **text strings**, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS).\n\nThat means that **any value** read in Python from an environment variable **will be a `str`**, and any conversion to a different type or any validation has to be done in code.\n\n## `PATH` Environment Variable\n\nThere is a **special** environment variable called **`PATH`** that is used by the operating systems (Linux, macOS, Windows) to find programs to run.\n\nThe value of the variable `PATH` is a long string that is made of directories separated by a colon `:` on Linux and macOS, and by a semicolon `;` on Windows.\n\nFor example, the `PATH` environment variable could look like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThis means that the system should look for programs in the directories:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nThis means that the system should look for programs in the directories:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nWhen you type a **command** in the terminal, the operating system **looks for** the program in **each of those directories** listed in the `PATH` environment variable.\n\nFor example, when you type `python` in the terminal, the operating system looks for a program called `python` in the **first directory** in that list.\n\nIf it finds it, then it will **use it**. Otherwise it keeps looking in the **other directories**.\n\n### Installing Python and Updating the `PATH`\n\nWhen you install Python, you might be asked if you want to update the `PATH` environment variable.\n\n//// tab | Linux, macOS\n\nLet's say you install Python and it ends up in a directory `/opt/custompython/bin`.\n\nIf you say yes to update the `PATH` environment variable, then the installer will add `/opt/custompython/bin` to the `PATH` environment variable.\n\nIt could look like this:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nThis way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one.\n\n////\n\n//// tab | Windows\n\nLet's say you install Python and it ends up in a directory `C:\\opt\\custompython\\bin`.\n\nIf you say yes to update the `PATH` environment variable, then the installer will add `C:\\opt\\custompython\\bin` to the `PATH` environment variable.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nThis way, when you type `python` in the terminal, the system will find the Python program in `C:\\opt\\custompython\\bin` (the last directory) and use that one.\n\n////\n\nThis way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one.\n\nSo, if you type:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nThe system will **find** the `python` program in `/opt/custompython/bin` and run it.\n\nIt would be roughly equivalent to typing:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nThe system will **find** the `python` program in `C:\\opt\\custompython\\bin\\python` and run it.\n\nIt would be roughly equivalent to typing:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nThis information will be useful when learning about [Virtual Environments](virtual-environments.md){.internal-link target=_blank}.\n\n## Conclusion\n\nWith this you should have a basic understanding of what **environment variables** are and how to use them in Python.\n\nYou can also read more about them in the <a href=\"https://en.wikipedia.org/wiki/Environment_variable\" class=\"external-link\" target=\"_blank\">Wikipedia for Environment Variable</a>.\n\nIn many cases it's not very obvious how environment variables would be useful and applicable right away. But they keep showing up in many different scenarios when you are developing, so it's good to know about them.\n\nFor example, you will need this information in the next section, about [Virtual Environments](virtual-environments.md).\n"
  },
  {
    "path": "docs/features.md",
    "content": "# Features\n\n## Designed for **FastAPI**\n\n**SQLModel** was created by the same <a href=\"https://tiangolo.com/\" class=\"external-link\" target=\"_blank\">author</a> of FastAPI.\n\n<a href=\"https://fastapi.tiangolo.com\" target=\"_blank\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" style=\"width: 20%;\"></a>\n\nIt follows the same design and ideas, and it was created to be the most intuitive way to interact with SQL databases in FastAPI applications.\n\nNevertheless, SQLModel is completely **independent** of FastAPI and can be used with any other type of application. You can still benefit from its features.\n\n## Just Modern Python\n\nIt's all based on standard <abbr title=\"Currently supported versions of Python\">modern **Python**</abbr> type annotations. No new syntax to learn. Just standard modern Python.\n\nIf you need a 2 minute refresher of how to use Python types (even if you don't use SQLModel or FastAPI), check the FastAPI tutorial section: <a href=\"https://fastapi.tiangolo.com/python-types/\" class=\"external-link\" target=\"_blank\">Python types intro</a>.\n\nYou will also see a 20 seconds refresher on the section [Tutorial - User Guide: First Steps](tutorial/index.md){.internal-link target=_blank}.\n\n## Editor support\n\n**SQLModel** was designed to be easy and intuitive to use to ensure the best development experience, with autocompletion everywhere.\n\nHere's how your editor might help you:\n\n* in <a href=\"https://code.visualstudio.com/\" class=\"external-link\" target=\"_blank\">Visual Studio Code</a>:\n\n<img class=\"shadow\" src=\"/img/index/autocompletion02.png\">\n\n* in <a href=\"https://www.jetbrains.com/pycharm/\" class=\"external-link\" target=\"_blank\">PyCharm</a>:\n\n<img class=\"shadow\" src=\"/img/features/autocompletion01.png\">\n\nYou will get completion for everything while writing the **minimum** amount of code.\n\nYou won't need to keep guessing the types of different attributes in your models, if they could be `None`, etc. Your editor will be able to help you with everything because **SQLModel** is based on **standard Python type annotations**.\n\n**SQLModel** adopts <a href=\"https://peps.python.org/pep-0681/\" class=\"external-link\" target=\"_blank\">PEP 681</a> for Python type annotations to ensure the **best developer experience**, so you will get inline errors and autocompletion even while creating new model instances.\n\n<img class=\"shadow\" src=\"/img/index/autocompletion01.png\">\n\n## Short\n\n**SQLModel** has **sensible defaults** for everything, with **optional configurations** everywhere.\n\nBut by default, it all **\"just works\"**.\n\nYou can start with the simplest (and most intuitive) type annotations for your data.\n\nAnd later, you can fine-tune everything with all the power of SQLAlchemy and Pydantic.\n\n## Based on Pydantic\n\n**SQLModel** is based on Pydantic and keeps the same design, syntax, and ideas.\n\nUnderneath, ✨ a **SQLModel** model is also a **Pydantic** model. ✨\n\nThere was a lot of research and effort dedicated to make it that way.\n\nThat means you get all of **Pydantic's features**, including automatic data **validation**, **serialization**, and **documentation**. You can use SQLModel in the same way you can use Pydantic.\n\nYou can even create SQLModel models that do *not* represent SQL tables. In that case, they would be **the same as Pydantic models**.\n\nThis is useful, in particular, because now you can create a SQL database model that *inherits* from another non-SQL model. You can use that to **reduce code duplication** a lot. It will also make your code more consistent, improve editor support, etc.\n\nThis makes it the perfect combination for working with SQL databases in **FastAPI** applications. 🚀\n\nYou will learn more about combining different models later in the tutorial.\n\n## Based on SQLAlchemy\n\n**SQLModel** is also based on SQLAlchemy and uses it for everything.\n\nUnderneath, ✨ a **SQLModel** model is also a **SQLAlchemy** model. ✨\n\nThere was **a lot** of research and effort dedicated to make it that way. In particular, there was a lot of effort and experimentation in making a single model be **both a SQLAlchemy model and a Pydantic** model at the same time.\n\nThat means that you get all the power, robustness, and certainty of SQLAlchemy, the <a href=\"https://lp.jetbrains.com/python-developers-survey-2024/#orms\" class=\"external-link\" target=\"_blank\">most widely used database library in Python</a>.\n\n**SQLModel** provides its own utilities to <abbr title=\"with type completion, type checks, etc.\">improve the developer experience</abbr>, but underneath, it uses all of SQLAlchemy.\n\nYou can even **combine** SQLModel models with SQLAlchemy models.\n\nSQLModel is designed to satisfy the **most common use cases** and to be as simple and convenient as possible for those cases, providing the best developer experience.\n\nBut when you have more exotic use cases that require more complex features, you can still plug SQLAlchemy directly into SQLModel and use all its features in your code.\n\n## Tested\n\n* 100% <abbr title=\"The amount of code that is automatically tested\">test coverage</abbr> (currently 97%, reaching 100% in the coming days/weeks).\n* 100% <abbr title=\"Python type annotations, with this your editor and external tools can give you better support\">type annotated</abbr> code base.\n"
  },
  {
    "path": "docs/help.md",
    "content": "# Help SQLModel - Get Help\n\nDo you like **SQLModel**?\n\nWould you like to help SQLModel, other users, and the author?\n\nOr would you like to get help with **SQLModel**?\n\nThere are very simple ways to help (several involve just one or two clicks).\n\nAnd there are several ways to get help too.\n\n## Subscribe to the FastAPI and Friends newsletter\n\nYou can subscribe to the (infrequent) <a href=\"https://fastapi.tiangolo.com/newsletter\" class=\"external-link\" target=\"_blank\">**FastAPI and friends** newsletter</a> to stay updated about:\n\n* News about FastAPI and friends, including SQLModel 🚀\n* Guides 📝\n* Features ✨\n* Breaking changes 🚨\n* Tips and tricks ✅\n\n## Star **SQLModel** in GitHub\n\nYou can \"star\" SQLModel in GitHub (clicking the star button at the top right): <a href=\"https://github.com/fastapi/sqlmodel\" class=\"external-link\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>. ⭐️\n\nBy adding a star, other users will be able to find it more easily and see that it has been already useful for others.\n\n## Watch the GitHub repository for releases\n\nYou can \"watch\" SQLModel in GitHub (clicking the \"watch\" button at the top right): <a href=\"https://github.com/fastapi/sqlmodel\" class=\"external-link\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>. 👀\n\nThere you can select \"Releases only\".\n\nBy doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **SQLModel** with bug fixes and new features.\n\n## Connect with the author\n\nYou can connect with <a href=\"https://tiangolo.com\" class=\"external-link\" target=\"_blank\">me (Sebastián Ramírez / `tiangolo`)</a>, the author.\n\nYou can:\n\n* <a href=\"https://github.com/tiangolo\" class=\"external-link\" target=\"_blank\">Follow me on **GitHub**</a>.\n    * See other Open Source projects I have created that could help you.\n    * Follow me to see when I create a new Open Source project.\n* <a href=\"https://twitter.com/tiangolo\" class=\"external-link\" target=\"_blank\">Follow me on **Twitter**</a>.\n    * Tell me how you use SQLModel (I love to hear that).\n    * Hear when I make announcements or release new tools.\n* <a href=\"https://www.linkedin.com/in/tiangolo/\" class=\"external-link\" target=\"_blank\">Connect with me on **Linkedin**</a>.\n    * Hear when I make announcements or release new tools (although I use Twitter more often 🤷‍♂).\n* Read what I write (or follow me) on <a href=\"https://dev.to/tiangolo\" class=\"external-link\" target=\"_blank\">**Dev.to**</a> or <a href=\"https://medium.com/@tiangolo\" class=\"external-link\" target=\"_blank\">**Medium**</a>.\n    * Read other ideas, articles, and read about tools I have created.\n    * Follow me to read when I publish something new.\n\n## Tweet about **SQLModel**\n\n<a href=\"https://twitter.com/compose/tweet?text=I'm loving SQLModel because... https://github.com/fastapi/sqlmodel cc: @tiangolo\" class=\"external-link\" target=\"_blank\">Tweet about **SQLModel**</a> and let me and others know why you like it. 🎉\n\nI love to hear about how **SQLModel** is being used, what you have liked in it, in which project/company are you using it, etc.\n\n## Help others with questions in GitHub\n\nYou can try and help others with their questions in:\n\n* <a href=\"https://github.com/fastapi/sqlmodel/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered\" class=\"external-link\" target=\"_blank\">GitHub Discussions</a>\n* <a href=\"https://github.com/fastapi/sqlmodel/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+\" class=\"external-link\" target=\"_blank\">GitHub Issues</a>\n\nIn many cases you might already know the answer for those questions. 🤓\n\nJust remember, the most important point is: try to be kind. People come with their frustrations and in many cases don't ask in the best way, but try as best as you can to be kind. 🤗\n\nThe idea is for the **SQLModel** community to be kind and welcoming. At the same time, don't accept bullying or disrespectful behavior towards others. We have to take care of each other.\n\n---\n\nHere's how to help others with questions (in discussions or issues):\n\n### Understand the question\n\n* Check if you can understand what is the **purpose** and use case of the person asking.\n\n* Then check if the question (the vast majority are questions) is **clear**.\n\n* In many cases the question asked is about an imaginary solution from the user, but there might be a **better** one. If you can understand the problem and use case better, you might be able to suggest a better **alternative solution**.\n\n* If you can't understand the question, ask for more **details**.\n\n### Reproduce the problem\n\nFor most of the cases and most of the questions there's something related to the person's **original code**.\n\nIn many cases they will only copy a fragment of the code, but that's not enough to **reproduce the problem**.\n\n* You can ask them to provide a <a href=\"https://stackoverflow.com/help/minimal-reproducible-example\" class=\"external-link\" target=\"_blank\">minimal, reproducible, example</a>, that you can **copy-paste** and run locally to see the same error or behavior they are seeing, or to understand their use case better.\n\n* If you are feeling too generous, you can try to **create an example** like that yourself, just based on the description of the problem. Just have in mind that this might take a lot of time and it might be better to ask them to clarify the problem first.\n\n### Suggest solutions\n\n* After being able to understand the question, you can give them a possible **answer**.\n\n* In many cases, it's better to understand their **underlying problem or use case**, because there might be a better way to solve it than what they are trying to do.\n\n### Ask to close\n\nIf they reply, there's a high chance you would have solved their problem, congrats, **you're a hero**! 🦸\n\n* Now, if that solved their problem, you can ask them to:\n\n    * In GitHub Discussions: mark the comment as the **answer**.\n    * In GitHub Issues: **close** the issue**.\n\n## Watch the GitHub repository\n\nYou can \"watch\" SQLModel in GitHub (clicking the \"watch\" button at the top right): <a href=\"https://github.com/fastapi/sqlmodel\" class=\"external-link\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>. 👀\n\nIf you select \"Watching\" instead of \"Releases only\" you will receive notifications when someone creates a new issue or question. You can also specify that you only want to be notified about new issues, or discussions, or PRs, etc.\n\nThen you can try and help them solve those questions.\n\n## Ask Questions\n\nYou can <a href=\"https://github.com/fastapi/sqlmodel/discussions/new?category=questions\" class=\"external-link\" target=\"_blank\">create a new question</a> in the GitHub repository, for example to:\n\n* Ask a **question** or ask about a **problem**.\n* Suggest a new **feature**.\n\n**Note**: if you do it, then I'm going to ask you to also help others. 😉\n\n## Review Pull Requests\n\nYou can help me review pull requests from others.\n\nAgain, please try your best to be kind. 🤗\n\n---\n\nHere's what to have in mind and how to review a pull request:\n\n### Understand the problem\n\n* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in a GitHub Discussion or issue.\n\n* There's also a good chance that the pull request is not actually needed because the problem can be solved in a **different way**. Then you can suggest or ask about that.\n\n### Don't worry about style\n\n* Don't worry too much about things like commit message styles, I will squash and merge customizing the commit manually.\n\n* Also don't worry about style rules, there are already automatized tools checking that.\n\nAnd if there's any other style or consistency need, I'll ask directly for that, or I'll add commits on top with the needed changes.\n\n### Check the code\n\n* Check and read the code, see if it makes sense, **run it locally** and see if it actually solves the problem.\n\n* Then **comment** saying that you did that, that's how I will know you really checked it.\n\n/// info\n\nUnfortunately, I can't simply trust PRs that just have several approvals.\n\nSeveral times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. 😅\n\nSo, it's really important that you actually read and run the code, and let me know in the comments that you did. 🤓\n\n///\n\n* If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well 🙈), so it's better if you can focus on the fundamental things.\n\n### Tests\n\n* Help me check that the PR has **tests**.\n\n* Check that the tests **fail** before the PR. 🚨\n\n* Then check that the tests **pass** after the PR. ✅\n\n* Many PRs don't have tests, you can **remind** them to add tests, or you can even **suggest** some tests yourself. That's one of the things that consume most time and you can help a lot with that.\n\n* Then also comment what you tried, that way I'll know that you checked it. 🤓\n\n## Create a Pull Request\n\nYou can [contribute](contributing.md){.internal-link target=_blank} to the source code with Pull Requests, for example:\n\n* To fix a typo you found on the documentation.\n* To propose new documentation sections.\n* To fix an existing issue/bug.\n    * Make sure to add tests.\n* To add a new feature.\n    * Make sure to add tests.\n    * Make sure to add documentation if it's relevant.\n\n## Help Maintain SQLModel\n\nHelp me maintain **SQLModel**! 🤓\n\nThere's a lot of work to do, and for most of it, **YOU** can do it.\n\nThe main tasks that you can do right now are:\n\n* [Help others with questions in GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (see the section above).\n* [Review Pull Requests](#review-pull-requests){.internal-link target=_blank} (see the section above).\n\nThose two tasks are what **consume time the most**. That's the main work of maintaining SQLModel.\n\nIf you can help me with that, **you are helping me maintain SQLModel** and making sure it keeps **advancing faster and better**. 🚀\n\n## Join the chat\n\nJoin the 👥 <a href=\"https://discord.gg/VQjSZaeJmf\" class=\"external-link\" target=\"_blank\">FastAPI and Friends Discord chat server</a> 👥 and hang out with others in the community. There's a `#sqlmodel` channel.\n\n/// tip\n\nFor questions, ask them in <a href=\"https://github.com/fastapi/sqlmodel/discussions/new?category=questions\" class=\"external-link\" target=\"_blank\">GitHub Discussions</a>, there's a much better chance you will receive help there.\n\nUse the chat only for other general conversations.\n\n///\n\n### Don't use the chat for questions\n\nHave in mind that as chats allow more \"free conversation\", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers.\n\nIn GitHub, the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat. 😅\n\nConversations in the chat are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation.\n\nOn the other side, there are thousands of users in the chat, so there's a high chance you'll find someone to talk to there, almost all the time. 😄\n\n## Sponsor the author\n\nYou can also financially support the author (me) through <a href=\"https://github.com/sponsors/tiangolo\" class=\"external-link\" target=\"_blank\">GitHub sponsors</a>.\n\nThere you could buy me a coffee ☕️ to say thanks. 😄\n\n## Sponsor the tools that power SQLModel\n\nAs you have seen in the documentation, SQLModel stands on the shoulders of giants, Pydantic and SQLAlchemy.\n\nYou can also sponsor:\n\n* <a href=\"https://github.com/sponsors/samuelcolvin\" class=\"external-link\" target=\"_blank\">Samuel Colvin (Pydantic)</a>\n* <a href=\"https://github.com/sponsors/sqlalchemy\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a>\n\n---\n\nThanks! 🚀\n"
  },
  {
    "path": "docs/index.md",
    "content": "<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://sqlmodel.tiangolo.com\"><img src=\"https://sqlmodel.tiangolo.com/img/logo-margin/logo-margin-vector.svg#only-light\" alt=\"SQLModel\"></a>\n<!-- only-mkdocs -->\n  <a href=\"https://sqlmodel.tiangolo.com\"><img src=\"img/logo-margin/logo-margin-white-vector.svg#only-dark\" alt=\"SQLModel\"></a>\n<!-- /only-mkdocs -->\n</p>\n<p align=\"center\">\n    <em>SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3ATest+event%3Apush+branch%3Amain\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/test.yml/badge.svg?event=push&branch=main\" alt=\"Test\">\n</a>\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3APublish\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/publish.yml/badge.svg\" alt=\"Publish\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/sqlmodel\" target=\"_blank\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/sqlmodel.svg\" alt=\"Coverage\">\n<a href=\"https://pypi.org/project/sqlmodel\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/v/sqlmodel?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n</p>\n\n---\n\n**Documentation**: <a href=\"https://sqlmodel.tiangolo.com\" target=\"_blank\">https://sqlmodel.tiangolo.com</a>\n\n**Source Code**: <a href=\"https://github.com/fastapi/sqlmodel\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>\n\n---\n\nSQLModel is a library for interacting with <abbr title='Also called \"Relational databases\"'>SQL databases</abbr> from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust.\n\n**SQLModel** is based on Python type annotations, and powered by <a href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\">Pydantic</a> and <a href=\"https://sqlalchemy.org/\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a>.\n\nThe key features are:\n\n* **Intuitive to write**: Great editor support. <abbr title=\"also known as auto-complete, autocompletion, IntelliSense\">Completion</abbr> everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.\n* **Easy to use**: It has sensible defaults and does a lot of work underneath to simplify the code you write.\n* **Compatible**: It is designed to be compatible with **FastAPI**, Pydantic, and SQLAlchemy.\n* **Extensible**: You have all the power of SQLAlchemy and Pydantic underneath.\n* **Short**: Minimize code duplication. A single type annotation does a lot of work. No need to duplicate models in SQLAlchemy and Pydantic.\n\n## Sponsors\n\n<!-- sponsors -->\n\n{% if sponsors %}\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n{% endif %}\n\n<!-- /sponsors -->\n\n## SQL Databases in FastAPI\n\n<a href=\"https://fastapi.tiangolo.com\" target=\"_blank\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" style=\"width: 20%;\"></a>\n\n**SQLModel** is designed to simplify interacting with SQL databases in <a href=\"https://fastapi.tiangolo.com\" class=\"external-link\" target=\"_blank\">FastAPI</a> applications, it was created by the same <a href=\"https://tiangolo.com/\" class=\"external-link\" target=\"_blank\">author</a>. 😁\n\nIt combines SQLAlchemy and Pydantic and tries to simplify the code you write as much as possible, allowing you to reduce the **code duplication to a minimum**, but while getting the **best developer experience** possible.\n\n**SQLModel** is, in fact, a thin layer on top of **Pydantic** and **SQLAlchemy**, carefully designed to be compatible with both.\n\n## Requirements\n\nA recent and currently supported <a href=\"https://www.python.org/downloads/\" class=\"external-link\" target=\"_blank\">version of Python</a>.\n\nAs **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel.\n\n## Installation\n\nMake sure you create a <a href=\"https://sqlmodel.tiangolo.com/virtual-environments/\" class=\"external-link\" target=\"_blank\">virtual environment</a>, activate it, and then install SQLModel, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\nSuccessfully installed sqlmodel\n```\n\n</div>\n\n## Example\n\nFor an introduction to databases, SQL, and everything else, see the <a href=\"https://sqlmodel.tiangolo.com/databases/\" target=\"_blank\">SQLModel documentation</a>.\n\nHere's a quick example. ✨\n\n### A SQL Table\n\nImagine you have a SQL table called `hero` with:\n\n* `id`\n* `name`\n* `secret_name`\n* `age`\n\nAnd you want it to have this data:\n\n| id | name | secret_name | age |\n-----|------|-------------|------|\n| 1  | Deadpond | Dive Wilson | null |\n| 2  | Spider-Boy | Pedro Parqueador | null |\n| 3  | Rusty-Man | Tommy Sharp | 48 |\n\n### Create a SQLModel Model\n\nThen you could create a **SQLModel** model like this:\n\n```Python\nfrom sqlmodel import Field, SQLModel\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n```\n\nThat class `Hero` is a **SQLModel** model, the equivalent of a SQL table in Python code.\n\nAnd each of those class attributes is equivalent to each **table column**.\n\n### Create Rows\n\nThen you could **create each row** of the table as an **instance** of the model:\n\n```Python\nhero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\nhero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\nhero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n```\n\nThis way, you can use conventional Python code with **classes** and **instances** that represent **tables** and **rows**, and that way communicate with the **SQL database**.\n\n### Editor Support\n\nEverything is designed for you to get the best developer experience possible, with the best editor support.\n\nIncluding **autocompletion**:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/autocompletion01.png\">\n\nAnd **inline errors**:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/inline-errors01.png\">\n\n### Write to the Database\n\nYou can learn a lot more about **SQLModel** by quickly following the **tutorial**, but if you need a taste right now of how to put all that together and save to the database, you can do this:\n\n```Python hl_lines=\"16  19  21-25\"\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nhero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\nhero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\nhero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n\nengine = create_engine(\"sqlite:///database.db\")\n\n\nSQLModel.metadata.create_all(engine)\n\nwith Session(engine) as session:\n    session.add(hero_1)\n    session.add(hero_2)\n    session.add(hero_3)\n    session.commit()\n```\n\nThat will save a **SQLite** database with the 3 heroes.\n\n### Select from the Database\n\nThen you could write queries to select from that same database, for example with:\n\n```Python hl_lines=\"13-17\"\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nengine = create_engine(\"sqlite:///database.db\")\n\nwith Session(engine) as session:\n    statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n    hero = session.exec(statement).first()\n    print(hero)\n```\n\n### Editor Support Everywhere\n\n**SQLModel** was carefully designed to give you the best developer experience and editor support, **even after selecting data** from the database:\n\n<img class=\"shadow\" src=\"https://sqlmodel.tiangolo.com/img/index/autocompletion02.png\">\n\n## SQLAlchemy and Pydantic\n\nThat class `Hero` is a **SQLModel** model.\n\nBut at the same time, ✨ it is a **SQLAlchemy** model ✨. So, you can combine it and use it with other SQLAlchemy models, or you could easily migrate applications with SQLAlchemy to **SQLModel**.\n\nAnd at the same time, ✨ it is also a **Pydantic** model ✨. You can use inheritance with it to define all your **data models** while avoiding code duplication. That makes it very easy to use with **FastAPI**.\n\n## License\n\nThis project is licensed under the terms of the [MIT license](https://github.com/fastapi/sqlmodel/blob/main/LICENSE).\n"
  },
  {
    "path": "docs/install.md",
    "content": "# Install **SQLModel**\n\nCreate a project directory, create a [virtual environment](virtual-environments.md){.internal-link target=_blank}, activate it, and then install **SQLModel**, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\nSuccessfully installed sqlmodel pydantic sqlalchemy\n```\n\n</div>\n\nAs **SQLModel** is built on top of <a href=\"https://www.sqlalchemy.org/\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a> and <a href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\">Pydantic</a>, when you install `sqlmodel` they will also be automatically installed.\n\n## Install DB Browser for SQLite\n\nRemember that [SQLite is a simple database in a single file](databases.md#a-single-file-database){.internal-link target=_blank}?\n\nFor most of the tutorial I'll use SQLite for the examples.\n\nPython has integrated support for SQLite, it is a single file read and processed from Python. And it doesn't need an [External Database Server](databases.md#a-server-database){.internal-link target=_blank}, so it will be perfect for learning.\n\nIn fact, SQLite is perfectly capable of handling quite big applications. At some point you might want to migrate to a server-based database like <a href=\"https://www.postgresql.org/\" class=\"external-link\" target=\"_blank\">PostgreSQL</a> (which is also free). But for now we'll stick to SQLite.\n\nThrough the tutorial I will show you SQL fragments, and Python examples. And I hope (and expect 🧐) you to actually run them, and verify that the database is working as expected and showing you the same data.\n\nTo be able to explore the SQLite file yourself, independent of Python code (and probably at the same time), I recommend you use <a href=\"https://sqlitebrowser.org/\" class=\"external-link\" target=\"_blank\">DB Browser for SQLite</a>.\n\nIt's a great and simple program to interact with SQLite databases (SQLite files) in a nice user interface.\n\n<img src=\"https://sqlitebrowser.org/images/screenshot.png\">\n\nGo ahead and <a href=\"https://sqlitebrowser.org/\" class=\"external-link\" target=\"_blank\">Install DB Browser for SQLite</a>, it's free.\n\n## Next Steps\n\nOkay, let's get going! On the next section we'll start the [Tutorial - User Guide](tutorial/index.md). 🚀\n"
  },
  {
    "path": "docs/js/custom.js",
    "content": "function setupTermynal() {\n    document.querySelectorAll(\".use-termynal\").forEach(node => {\n        node.style.display = \"block\";\n        new Termynal(node, {\n            lineDelay: 500\n        });\n    });\n    const progressLiteralStart = \"---> 100%\";\n    const promptLiteralStart = \"$ \";\n    const customPromptLiteralStart = \"# \";\n    const termynalActivateClass = \"termy\";\n    let termynals = [];\n\n    function createTermynals() {\n        document\n            .querySelectorAll(`.${termynalActivateClass} .highlight code`)\n            .forEach(node => {\n                const text = node.textContent;\n                const lines = text.split(\"\\n\");\n                const useLines = [];\n                let buffer = [];\n                function saveBuffer() {\n                    if (buffer.length) {\n                        let isBlankSpace = true;\n                        buffer.forEach(line => {\n                            if (line) {\n                                isBlankSpace = false;\n                            }\n                        });\n                        dataValue = {};\n                        if (isBlankSpace) {\n                            dataValue[\"delay\"] = 0;\n                        }\n                        if (buffer[buffer.length - 1] === \"\") {\n                            // A last single <br> won't have effect\n                            // so put an additional one\n                            buffer.push(\"\");\n                        }\n                        const bufferValue = buffer.join(\"<br>\");\n                        dataValue[\"value\"] = bufferValue;\n                        useLines.push(dataValue);\n                        buffer = [];\n                    }\n                }\n                for (let line of lines) {\n                    if (line === progressLiteralStart) {\n                        saveBuffer();\n                        useLines.push({\n                            type: \"progress\"\n                        });\n                    } else if (line.startsWith(promptLiteralStart)) {\n                        saveBuffer();\n                        const value = line.replace(promptLiteralStart, \"\").trimEnd();\n                        useLines.push({\n                            type: \"input\",\n                            value: value\n                        });\n                    } else if (line.startsWith(\"// \")) {\n                        saveBuffer();\n                        const value = \"💬 \" + line.replace(\"// \", \"\").trimEnd();\n                        useLines.push({\n                            value: value,\n                            class: \"termynal-comment\",\n                            delay: 0\n                        });\n                    } else if (line.startsWith(customPromptLiteralStart)) {\n                        saveBuffer();\n                        const promptStart = line.indexOf(promptLiteralStart);\n                        if (promptStart === -1) {\n                            console.error(\"Custom prompt found but no end delimiter\", line)\n                        }\n                        const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, \"\")\n                        let value = line.slice(promptStart + promptLiteralStart.length);\n                        useLines.push({\n                            type: \"input\",\n                            value: value,\n                            prompt: prompt\n                        });\n                    } else {\n                        buffer.push(line);\n                    }\n                }\n                saveBuffer();\n                const inputCommands = useLines.filter(line => line.type === \"input\").map(line => line.value).join(\"\\n\");\n                node.textContent = inputCommands;\n                const div = document.createElement(\"div\");\n                node.style.display = \"none\";\n                node.after(div);\n                const termynal = new Termynal(div, {\n                    lineData: useLines,\n                    noInit: true,\n                    lineDelay: 500\n                });\n                termynals.push(termynal);\n            });\n    }\n\n    function loadVisibleTermynals() {\n        termynals = termynals.filter(termynal => {\n            if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) {\n                termynal.init();\n                return false;\n            }\n            return true;\n        });\n    }\n    window.addEventListener(\"scroll\", loadVisibleTermynals);\n    createTermynals();\n    loadVisibleTermynals();\n}\n\nfunction openLinksInNewTab() {\n    const siteUrl = document.querySelector(\"link[rel='canonical']\")?.href\n        || window.location.origin;\n    const siteOrigin = new URL(siteUrl).origin;\n    document.querySelectorAll(\".md-content a[href]\").forEach(a => {\n        if (a.getAttribute(\"target\") === \"_self\") return;\n        const href = a.getAttribute(\"href\");\n        if (!href) return;\n        try {\n            const url = new URL(href, window.location.href);\n            // Skip same-page anchor links (only the hash differs)\n            if (url.origin === window.location.origin\n                && url.pathname === window.location.pathname\n                && url.search === window.location.search) return;\n            if (!a.hasAttribute(\"target\")) {\n                a.setAttribute(\"target\", \"_blank\");\n                a.setAttribute(\"rel\", \"noopener\");\n            }\n            if (url.origin !== siteOrigin) {\n                a.dataset.externalLink = \"\";\n            } else {\n                a.dataset.internalLink = \"\";\n            }\n        } catch (_) {}\n    });\n}\n\nasync function main() {\n    setupTermynal();\n    openLinksInNewTab();\n}\n\ndocument$.subscribe(() => {\n    main()\n})\n"
  },
  {
    "path": "docs/js/termynal.js",
    "content": "/**\n * termynal.js\n * A lightweight, modern and extensible animated terminal window, using\n * async/await.\n *\n * @author Ines Montani <ines@ines.io>\n * @version 0.0.1\n * @license MIT\n */\n\n'use strict';\n\n/** Generate a terminal widget. */\nclass Termynal {\n    /**\n     * Construct the widget's settings.\n     * @param {(string|Node)=} container - Query selector or container element.\n     * @param {Object=} options - Custom settings.\n     * @param {string} options.prefix - Prefix to use for data attributes.\n     * @param {number} options.startDelay - Delay before animation, in ms.\n     * @param {number} options.typeDelay - Delay between each typed character, in ms.\n     * @param {number} options.lineDelay - Delay between each line, in ms.\n     * @param {number} options.progressLength - Number of characters displayed as progress bar.\n     * @param {string} options.progressChar – Character to use for progress bar, defaults to █.\n\t * @param {number} options.progressPercent - Max percent of progress.\n     * @param {string} options.cursor – Character to use for cursor, defaults to ▋.\n     * @param {Object[]} lineData - Dynamically loaded line data objects.\n     * @param {boolean} options.noInit - Don't initialise the animation.\n     */\n    constructor(container = '#termynal', options = {}) {\n        this.container = (typeof container === 'string') ? document.querySelector(container) : container;\n        this.pfx = `data-${options.prefix || 'ty'}`;\n        this.originalStartDelay = this.startDelay = options.startDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;\n        this.originalTypeDelay = this.typeDelay = options.typeDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;\n        this.originalLineDelay = this.lineDelay = options.lineDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;\n        this.progressLength = options.progressLength\n            || parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;\n        this.progressChar = options.progressChar\n            || this.container.getAttribute(`${this.pfx}-progressChar`) || '█';\n\t\tthis.progressPercent = options.progressPercent\n            || parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;\n        this.cursor = options.cursor\n            || this.container.getAttribute(`${this.pfx}-cursor`) || '▋';\n        this.lineData = this.lineDataToElements(options.lineData || []);\n        this.loadLines()\n        if (!options.noInit) this.init()\n    }\n\n    loadLines() {\n        // Load all the lines and create the container so that the size is fixed\n        // Otherwise it would be changing and the user viewport would be constantly\n        // moving as she/he scrolls\n        const finish = this.generateFinish()\n        finish.style.visibility = 'hidden'\n        this.container.appendChild(finish)\n        // Appends dynamically loaded lines to existing line elements.\n        this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);\n        for (let line of this.lines) {\n            line.style.visibility = 'hidden'\n            this.container.appendChild(line)\n        }\n        const restart = this.generateRestart()\n        restart.style.visibility = 'hidden'\n        this.container.appendChild(restart)\n        this.container.setAttribute('data-termynal', '');\n    }\n\n    /**\n     * Initialise the widget, get lines, clear container and start animation.\n     */\n    init() {\n        /**\n         * Calculates width and height of Termynal container.\n         * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.\n         */\n        const containerStyle = getComputedStyle(this.container);\n        this.container.style.width = containerStyle.width !== '0px' ?\n            containerStyle.width : undefined;\n        this.container.style.minHeight = containerStyle.height !== '0px' ?\n            containerStyle.height : undefined;\n\n        this.container.setAttribute('data-termynal', '');\n        this.container.innerHTML = '';\n        for (let line of this.lines) {\n            line.style.visibility = 'visible'\n        }\n        this.start();\n    }\n\n    /**\n     * Start the animation and rener the lines depending on their data attributes.\n     */\n    async start() {\n        this.addFinish()\n        await this._wait(this.startDelay);\n\n        for (let line of this.lines) {\n            const type = line.getAttribute(this.pfx);\n            const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;\n\n            if (type == 'input') {\n                line.setAttribute(`${this.pfx}-cursor`, this.cursor);\n                await this.type(line);\n                await this._wait(delay);\n            }\n\n            else if (type == 'progress') {\n                await this.progress(line);\n                await this._wait(delay);\n            }\n\n            else {\n                this.container.appendChild(line);\n                await this._wait(delay);\n            }\n\n            line.removeAttribute(`${this.pfx}-cursor`);\n        }\n        this.addRestart()\n        this.finishElement.style.visibility = 'hidden'\n        this.lineDelay = this.originalLineDelay\n        this.typeDelay = this.originalTypeDelay\n        this.startDelay = this.originalStartDelay\n    }\n\n    generateRestart() {\n        const restart = document.createElement('a')\n        restart.onclick = (e) => {\n            e.preventDefault()\n            this.container.innerHTML = ''\n            this.init()\n        }\n        restart.href = '#'\n        restart.setAttribute('data-terminal-control', '')\n        restart.innerHTML = \"restart ↻\"\n        return restart\n    }\n\n    generateFinish() {\n        const finish = document.createElement('a')\n        finish.onclick = (e) => {\n            e.preventDefault()\n            this.lineDelay = 0\n            this.typeDelay = 0\n            this.startDelay = 0\n        }\n        finish.href = '#'\n        finish.setAttribute('data-terminal-control', '')\n        finish.innerHTML = \"fast →\"\n        this.finishElement = finish\n        return finish\n    }\n\n    addRestart() {\n        const restart = this.generateRestart()\n        this.container.appendChild(restart)\n    }\n\n    addFinish() {\n        const finish = this.generateFinish()\n        this.container.appendChild(finish)\n    }\n\n    /**\n     * Animate a typed line.\n     * @param {Node} line - The line element to render.\n     */\n    async type(line) {\n        const chars = [...line.textContent];\n        line.textContent = '';\n        this.container.appendChild(line);\n\n        for (let char of chars) {\n            const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;\n            await this._wait(delay);\n            line.textContent += char;\n        }\n    }\n\n    /**\n     * Animate a progress bar.\n     * @param {Node} line - The line element to render.\n     */\n    async progress(line) {\n        const progressLength = line.getAttribute(`${this.pfx}-progressLength`)\n            || this.progressLength;\n        const progressChar = line.getAttribute(`${this.pfx}-progressChar`)\n            || this.progressChar;\n        const chars = progressChar.repeat(progressLength);\n\t\tconst progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)\n\t\t\t|| this.progressPercent;\n        line.textContent = '';\n        this.container.appendChild(line);\n\n        for (let i = 1; i < chars.length + 1; i++) {\n            await this._wait(this.typeDelay);\n            const percent = Math.round(i / chars.length * 100);\n            line.textContent = `${chars.slice(0, i)} ${percent}%`;\n\t\t\tif (percent>progressPercent) {\n\t\t\t\tbreak;\n\t\t\t}\n        }\n    }\n\n    /**\n     * Helper function for animation delays, called with `await`.\n     * @param {number} time - Timeout, in ms.\n     */\n    _wait(time) {\n        return new Promise(resolve => setTimeout(resolve, time));\n    }\n\n    /**\n     * Converts line data objects into line elements.\n     *\n     * @param {Object[]} lineData - Dynamically loaded lines.\n     * @param {Object} line - Line data object.\n     * @returns {Element[]} - Array of line elements.\n     */\n    lineDataToElements(lineData) {\n        return lineData.map(line => {\n            let div = document.createElement('div');\n            div.innerHTML = `<span ${this._attributes(line)}>${line.value || ''}</span>`;\n\n            return div.firstElementChild;\n        });\n    }\n\n    /**\n     * Helper function for generating attributes string.\n     *\n     * @param {Object} line - Line data object.\n     * @returns {string} - String of attributes.\n     */\n    _attributes(line) {\n        let attrs = '';\n        for (let prop in line) {\n            // Custom add class\n            if (prop === 'class') {\n                attrs += ` class=${line[prop]} `\n                continue\n            }\n            if (prop === 'type') {\n                attrs += `${this.pfx}=\"${line[prop]}\" `\n            } else if (prop !== 'value') {\n                attrs += `${this.pfx}-${prop}=\"${line[prop]}\" `\n            }\n        }\n        return attrs;\n    }\n}\n\n/**\n* HTML API: If current script has container(s) specified, initialise Termynal.\n*/\nif (document.currentScript.hasAttribute('data-termynal-container')) {\n    const containers = document.currentScript.getAttribute('data-termynal-container');\n    containers.split('|')\n        .forEach(container => new Termynal(container))\n}\n"
  },
  {
    "path": "docs/learn/index.md",
    "content": "# Learn\n\nLearn how to use **SQLModel** here.\n\nThis includes an introduction to **databases**, **SQL**, how to interact with databases from **code** and more.\n\nYou could consider this a **book**, a **course**, and the **official** recommended way to learn **SQLModel**. 😎\n"
  },
  {
    "path": "docs/management-tasks.md",
    "content": "# Repository Management Tasks\n\nThese are the tasks that can be performed to manage the SQLModel repository by [team members](./management.md#team){.internal-link target=_blank}.\n\n/// tip\n\nThis section is useful only to a handful of people, team members with permissions to manage the repository. You can probably skip it. 😉\n\n///\n\n...so, you are a [team member of SQLModel](./management.md#team){.internal-link target=_blank}? Wow, you are so cool! 😎\n\nYou can help with everything on [Help SQLModel - Get Help](./help.md){.internal-link target=_blank} the same ways as external contributors. But additionally, there are some tasks that only you (as part of the team) can perform.\n\nHere are the general instructions for the tasks you can perform.\n\nThanks a lot for your help. 🙇\n\n## Be Nice\n\nFirst of all, be nice. 😊\n\nYou probably are super nice if you were added to the team, but it's worth mentioning it. 🤓\n\n### When Things are Difficult\n\nWhen things are great, everything is easier, so that doesn't need much instructions. But when things are difficult, here are some guidelines.\n\nTry to find the good side. In general, if people are not being unfriendly, try to thank their effort and interest, even if you disagree with the main subject (discussion, PR), just thank them for being interested in the project, or for having dedicated some time to try to do something.\n\nIt's difficult to convey emotion in text, use emojis to help. 😅\n\nIn discussions and PRs, in many cases, people bring their frustration and show it without filter, in many cases exaggerating, complaining, being entitled, etc. That's really not nice, and when it happens, it lowers our priority to solve their problems. But still, try to breath, and be gentle with your answers.\n\nTry to avoid using bitter sarcasm or potentially passive-aggressive comments. If something is wrong, it's better to be direct (try to be gentle) than sarcastic.\n\nTry to be as specific and objective as possible, avoid generalizations.\n\nFor conversations that are more difficult, for example to reject a PR, you can ask me (@tiangolo) to handle it directly.\n\n## Edit PR Titles\n\n* Edit the PR title to start with an emoji from <a href=\"https://gitmoji.dev/\" class=\"external-link\" target=\"_blank\">gitmoji</a>.\n    * Use the emoji character, not the GitHub code. So, use `🐛` instead of `:bug:`. This is so that it shows up correctly outside of GitHub, for example in the release notes.\n* Start the title with a verb. For example `Add`, `Refactor`, `Fix`, etc. This way the title will say the action that the PR does. Like `Add support for teleporting`, instead of `Teleporting wasn't working, so this PR fixes it`.\n* Edit the text of the PR title to start in \"imperative\", like giving an order. So, instead of `Adding support for teleporting` use `Add support for teleporting`.\n* Try to make the title descriptive about what it achieves. If it's a feature, try to describe it, for example `Add support for teleporting` instead of `Create TeleportAdapter class`.\n* Do not finish the title with a period (`.`).\n\nOnce the PR is merged, a GitHub Action (<a href=\"https://github.com/tiangolo/latest-changes\" class=\"external-link\" target=\"_blank\">latest-changes</a>) will use the PR title to update the latest changes automatically.\n\nSo, having a nice PR title will not only look nice in GitHub, but also in the release notes. 📝\n\n## Add Labels to PRs\n\nThe same GitHub Action <a href=\"https://github.com/tiangolo/latest-changes\" class=\"external-link\" target=\"_blank\">latest-changes</a> uses one label in the PR to decide the section in the release notes to put this PR in.\n\nMake sure you use a supported label from the <a href=\"https://github.com/tiangolo/latest-changes#using-labels\" class=\"external-link\" target=\"_blank\">latest-changes list of labels</a>:\n\n* `breaking`: Breaking Changes\n    * Existing code will break if they update the version without changing their code. This rarely happens, so this label is not frequently used.\n* `security`: Security Fixes\n    * This is for security fixes, like vulnerabilities. It would almost never be used.\n* `feature`: Features\n    * New features, adding support for things that didn't exist before.\n* `bug`: Fixes\n    * Something that was supported didn't work, and this fixes it. There are many PRs that claim to be bug fixes because the user is doing something in an unexpected way that is not supported, but they considered it what should be supported by default. Many of these are actually features or refactors. But in some cases there's an actual bug.\n* `refactor`: Refactors\n    * This is normally for changes to the internal code that don't change the behavior. Normally it improves maintainability, or enables future features, etc.\n* `upgrade`: Upgrades\n    * This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies or GitHub Action versions should be marked as `internal`, not `upgrade`.\n* `docs`: Docs\n    * Changes in docs. This includes updating the docs, fixing typos. But it doesn't include changes to translations.\n    * You can normally quickly detect it by going to the \"Files changed\" tab in the PR and checking if the updated file(s) starts with `docs/en/docs`. The original version of the docs is always in English, so in `docs/en/docs`.\n* `internal`: Internal\n    * Use this for changes that only affect how the repo is managed. For example upgrades to internal dependencies, changes in GitHub Actions or scripts, etc.\n\n/// tip\n\nSome tools like Dependabot, will add some labels, like `dependencies`, but have in mind that this label is not used by the `latest-changes` GitHub Action, so it won't be used in the release notes. Please make sure one of the labels above is added.\n\n///\n\n## Review PRs\n\n* If a PR doesn't explain what it does or why, if it seems like it could be useful, ask for more information. Otherwise, feel free to close it.\n\n* If a PR seems to be spam, meaningless, only to change statistics (to appear as \"contributor\") or similar, you can simply mark it as `invalid`, and it will be automatically closed.\n\n* If a PR seems to be AI generated, and seems like reviewing it would take more time from you than the time it took to write the prompt, mark it as `maybe-ai`, and it will be automatically closed.\n\n* A PR should have a specific use case that it is solving.\n\n* If the PR is for a feature, it should have docs.\n    * Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use.\n* The docs should include a source example file, not write Python directly in Markdown.\n* If the source example(s) file can have different syntax for different Python versions, there should be different versions of the file, and they should be shown in tabs in the docs.\n* There should be tests testing the source example.\n* Before the PR is applied, the new tests should fail.\n* After applying the PR, the new tests should pass.\n* Coverage should stay at 100%.\n* If you see the PR makes sense, or we discussed it and considered it should be accepted, you can add commits on top of the PR to tweak it, to add docs, tests, format, refactor, remove extra files, etc.\n* Feel free to comment in the PR to ask for more information, to suggest changes, etc.\n* Once you think the PR is ready, move it in the internal GitHub project for me to review it.\n\n## Dependabot PRs\n\nDependabot will create PRs to update dependencies for several things, and those PRs all look similar, but some are way more delicate than others.\n\n* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml` in the main dependencies, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.\n* If the PR updates one of the internal dependencies, for example the group `dev` in `pyproject.toml`, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎\n\n## Mark GitHub Discussions Answers\n\nWhen a question in GitHub Discussions has been answered, mark the answer by clicking \"Mark as answer\".\n\nYou can filter discussions by <a href=\"https://github.com/fastapi/sqlmodel/discussions/categories/questions?discussions_q=category:Questions+is:open+is:unanswered\" class=\"external-link\" target=\"_blank\">`Questions` that are `Unanswered`</a>.\n"
  },
  {
    "path": "docs/management.md",
    "content": "# Repository Management\n\nHere's a short description of how the SQLModel repository is managed and maintained.\n\n## Owner\n\nI, <a href=\"https://github.com/tiangolo\" target=\"_blank\">@tiangolo</a>, am the creator and owner of the SQLModel repository. 🤓\n\nI normally give the final review to each PR before merging them. I make the final decisions on the project, I'm the <a href=\"https://en.wikipedia.org/wiki/Benevolent_dictator_for_life\" class=\"external-link\" target=\"_blank\"><abbr title=\"Benevolent Dictator For Life\">BDFL</abbr></a>. 😅\n\n## Team\n\nThere's a team of people that help manage and maintain the project. 😎\n\nThey have different levels of permissions and [specific instructions](./management-tasks.md){.internal-link target=_blank}.\n\nSome of the tasks they can perform include:\n\n* Adding labels to PRs.\n* Editing PR titles.\n* Adding commits on top of PRs to tweak them.\n* Mark answers in GitHub Discussions questions, etc.\n* Merge some specific types of PRs.\n\nJoining the team is by invitation only, and I could update or remove permissions, instructions, or membership.\n\n### Team Members\n\nThis is the current list of team members. 😎\n\n<div class=\"user-list user-list-center\">\n{% for user in members[\"members\"] %}\n\n<div class=\"user\"><a href=\"https://github.com/{{ user.login }}\" target=\"_blank\"><div class=\"avatar-wrapper\"><img src=\"https://github.com/{{ user.login }}.png\"/></div><div class=\"title\">@{{ user.login }}</div></a></div>\n{% endfor %}\n\n</div>\n\nAdditional to them, there's a large community of people helping each other and getting involved in the projects in different ways.\n\n## External Contributions\n\nExternal contributions are very welcome and appreciated, including answering questions, submitting PRs, etc. 🙇‍♂️\n\nThere are many ways to [help maintain SQLModel](./help.md){.internal-link target=_blank}.\n"
  },
  {
    "path": "docs/overrides/main.html",
    "content": "{% extends \"base.html\" %}\n"
  },
  {
    "path": "docs/release-notes.md",
    "content": "# Release Notes\n\n## Latest Changes\n\n### Fixes\n\n* 🐛 Fix `tuple_` return type annotation. PR [#1639](https://github.com/fastapi/sqlmodel/pull/1639) by [@kakeruzoku](https://github.com/kakeruzoku).\n\n### Docs\n\n* 📝 Fix ambiguous phrasing regarding `HeroPublicWithTeam` model. PR [#1678](https://github.com/fastapi/sqlmodel/pull/1678) by [@berkaykrc](https://github.com/berkaykrc).\n* 🔨 Handle external links `target=_blank` and CSS automatically in JS and CSS. PR [#1799](https://github.com/fastapi/sqlmodel/pull/1799) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Document `.in_()` method. PR [#619](https://github.com/fastapi/sqlmodel/pull/619) by [@masylum](https://github.com/masylum).\n* 📝 Fix small typos in the documentation. PR [#1641](https://github.com/fastapi/sqlmodel/pull/1641) by [@svlandeg](https://github.com/svlandeg).\n\n### Internal\n\n* ⬆ Bump mkdocs-material from 9.7.5 to 9.7.6. PR [#1825](https://github.com/fastapi/sqlmodel/pull/1825) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.15.6 to 0.15.7. PR [#1826](https://github.com/fastapi/sqlmodel/pull/1826) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.3.5 to 0.3.6. PR [#1817](https://github.com/fastapi/sqlmodel/pull/1817) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 📌 Update internal dependency limits. PR [#1809](https://github.com/fastapi/sqlmodel/pull/1809) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump ruff from 0.15.5 to 0.15.6. PR [#1814](https://github.com/fastapi/sqlmodel/pull/1814) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump cairosvg from 2.8.2 to 2.9.0. PR [#1813](https://github.com/fastapi/sqlmodel/pull/1813) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump dorny/paths-filter from 3 to 4. PR [#1812](https://github.com/fastapi/sqlmodel/pull/1812) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump black from 26.3.0 to 26.3.1. PR [#1811](https://github.com/fastapi/sqlmodel/pull/1811) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.7.4 to 9.7.5. PR [#1808](https://github.com/fastapi/sqlmodel/pull/1808) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.3.4 to 0.3.5. PR [#1807](https://github.com/fastapi/sqlmodel/pull/1807) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump black from 26.1.0 to 26.3.0. PR [#1803](https://github.com/fastapi/sqlmodel/pull/1803) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.15.4 to 0.15.5. PR [#1801](https://github.com/fastapi/sqlmodel/pull/1801) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.7.3 to 9.7.4. PR [#1797](https://github.com/fastapi/sqlmodel/pull/1797) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump sqlalchemy from 2.0.47 to 2.0.48. PR [#1793](https://github.com/fastapi/sqlmodel/pull/1793) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.3.3 to 0.3.4. PR [#1794](https://github.com/fastapi/sqlmodel/pull/1794) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.134.0 to 0.135.1. PR [#1795](https://github.com/fastapi/sqlmodel/pull/1795) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.133.1 to 0.134.0. PR [#1792](https://github.com/fastapi/sqlmodel/pull/1792) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.15.2 to 0.15.4. PR [#1790](https://github.com/fastapi/sqlmodel/pull/1790) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/download-artifact from 7 to 8. PR [#1789](https://github.com/fastapi/sqlmodel/pull/1789) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/upload-artifact from 6 to 7. PR [#1788](https://github.com/fastapi/sqlmodel/pull/1788) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.133.0 to 0.133.1. PR [#1787](https://github.com/fastapi/sqlmodel/pull/1787) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.7.2 to 9.7.3. PR [#1782](https://github.com/fastapi/sqlmodel/pull/1782) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.132.0 to 0.133.0. PR [#1781](https://github.com/fastapi/sqlmodel/pull/1781) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump sqlalchemy from 2.0.46 to 2.0.47. PR [#1783](https://github.com/fastapi/sqlmodel/pull/1783) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pytest from 8.4.2 to 9.0.2. PR [#1780](https://github.com/fastapi/sqlmodel/pull/1780) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocstrings[python] from 0.30.1 to 1.0.3. PR [#1776](https://github.com/fastapi/sqlmodel/pull/1776) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.23.2 to 0.24.1. PR [#1777](https://github.com/fastapi/sqlmodel/pull/1777) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.15.1 to 0.15.2. PR [#1779](https://github.com/fastapi/sqlmodel/pull/1779) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.129.0 to 0.132.0. PR [#1778](https://github.com/fastapi/sqlmodel/pull/1778) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update all dependencies to use `griffelib` instead of `griffe`. PR [#1775](https://github.com/fastapi/sqlmodel/pull/1775) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump mkdocs-material from 9.7.1 to 9.7.2. PR [#1764](https://github.com/fastapi/sqlmodel/pull/1764) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pillow from 11.3.0 to 12.1.1. PR [#1770](https://github.com/fastapi/sqlmodel/pull/1770) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pydantic-settings from 2.12.0 to 2.13.1. PR [#1771](https://github.com/fastapi/sqlmodel/pull/1771) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.128.8 to 0.129.0. PR [#1769](https://github.com/fastapi/sqlmodel/pull/1769) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump black from 25.12.0 to 26.1.0. PR [#1768](https://github.com/fastapi/sqlmodel/pull/1768) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.37\n\n### Internal\n\n* 👷 Fix build CI to not attempt to build `sqlmodel-slim`. PR [#1773](https://github.com/fastapi/sqlmodel/pull/1773) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.36\n\n### Internal\n\n* ➖ Drop support for `sqlmodel-slim`, no more versions will be released, use only `sqmodel`. PR [#1772](https://github.com/fastapi/sqlmodel/pull/1772) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.35\n\n### Breaking Changes\n\n* ➖ Drop support for Python 3.9. PR [#1766](https://github.com/fastapi/sqlmodel/pull/1766) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* 🔨 Add script to remove Python 3.9 files, migrate to Python 3.10. PR [#1767](https://github.com/fastapi/sqlmodel/pull/1767) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump prek from 0.3.2 to 0.3.3. PR [#1761](https://github.com/fastapi/sqlmodel/pull/1761) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.23.1 to 0.23.2. PR [#1760](https://github.com/fastapi/sqlmodel/pull/1760) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.34\n\n### Internal\n\n* 👷 Enable tests with lower and upper bound versions. PR [#1735](https://github.com/fastapi/sqlmodel/pull/1735) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump ruff from 0.15.0 to 0.15.1. PR [#1758](https://github.com/fastapi/sqlmodel/pull/1758) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.23.0 to 0.23.1. PR [#1759](https://github.com/fastapi/sqlmodel/pull/1759) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.21.2 to 0.23.0. PR [#1756](https://github.com/fastapi/sqlmodel/pull/1756) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.128.7 to 0.128.8. PR [#1755](https://github.com/fastapi/sqlmodel/pull/1755) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.33\n\n### Docs\n\n* ✏️ Fix typos in inline comment in `expression.py`. PR [#1747](https://github.com/fastapi/sqlmodel/pull/1747) by [@veeceey](https://github.com/veeceey).\n* 📝 Fix async example in `session.execute()` docstring & deprecation message. PR [#1643](https://github.com/fastapi/sqlmodel/pull/1643) by [@DanielLeviLucas](https://github.com/DanielLeviLucas).\n* 📝 Update `management-tasks.md` to be in line with `management-tasks.md` in FastAPI repo. PR [#1743](https://github.com/fastapi/sqlmodel/pull/1743) by [@YuriiMotov](https://github.com/YuriiMotov).\n\n### Internal\n\n* 🔨 Update build script for `sqlmodel-slim`. PR [#1754](https://github.com/fastapi/sqlmodel/pull/1754) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump fastapi from 0.128.6 to 0.128.7. PR [#1751](https://github.com/fastapi/sqlmodel/pull/1751) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.21.1 to 0.21.2. PR [#1752](https://github.com/fastapi/sqlmodel/pull/1752) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Update build setup for `sqlmodel-slim`, deprecate it, and make it only depend on `sqlmodel`. PR [#1753](https://github.com/fastapi/sqlmodel/pull/1753) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump fastapi from 0.128.3 to 0.128.6. PR [#1750](https://github.com/fastapi/sqlmodel/pull/1750) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.128.1 to 0.128.3. PR [#1746](https://github.com/fastapi/sqlmodel/pull/1746) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.3.1 to 0.3.2. PR [#1745](https://github.com/fastapi/sqlmodel/pull/1745) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump fastapi from 0.128.0 to 0.128.1. PR [#1742](https://github.com/fastapi/sqlmodel/pull/1742) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Update `ValidationError` schema in FastAPI-related tests to be compatible with FastAPI 0.128.1+. PR [#1744](https://github.com/fastapi/sqlmodel/pull/1744) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ⬆ Bump ruff from 0.14.14 to 0.15.0. PR [#1740](https://github.com/fastapi/sqlmodel/pull/1740) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Add generate-readme to pre-commit. PR [#1741](https://github.com/fastapi/sqlmodel/pull/1741) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Run mypy by pre-commit. PR [#1738](https://github.com/fastapi/sqlmodel/pull/1738) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ⬆ Bump prek from 0.3.0 to 0.3.1. PR [#1739](https://github.com/fastapi/sqlmodel/pull/1739) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.32\n\n### Fixes\n\n* 🐛 Fix support for `Annotated` fields with Pydantic 2.12+. PR [#1607](https://github.com/fastapi/sqlmodel/pull/1607) by [@vimota](https://github.com/vimota).\n\n### Refactors\n\n* ♻️ Import `Literal` from the `typing` module directly. PR [#1699](https://github.com/fastapi/sqlmodel/pull/1699) by [@svlandeg](https://github.com/svlandeg).\n\n### Docs\n\n* 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs. PR [#1712](https://github.com/fastapi/sqlmodel/pull/1712) by [@alejsdev](https://github.com/alejsdev).\n* 🐛 Fix copy button in `custom.js`. PR [#1711](https://github.com/fastapi/sqlmodel/pull/1711) by [@alejsdev](https://github.com/alejsdev).\n* 📝 Remove duplicated word in `read-relationships.md`. PR [#1705](https://github.com/fastapi/sqlmodel/pull/1705) by [@stefmolin](https://github.com/stefmolin).\n\n### Internal\n\n* ⬆ Bump ruff from 0.14.13 to 0.14.14. PR [#1721](https://github.com/fastapi/sqlmodel/pull/1721) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.2.30 to 0.3.0. PR [#1720](https://github.com/fastapi/sqlmodel/pull/1720) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Ensure that an edit to `uv.lock` gets the `internal` label. PR [#1719](https://github.com/fastapi/sqlmodel/pull/1719) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump sqlalchemy from 2.0.45 to 2.0.46. PR [#1717](https://github.com/fastapi/sqlmodel/pull/1717) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.21.0 to 0.21.1. PR [#1715](https://github.com/fastapi/sqlmodel/pull/1715) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.10 to 0.14.13. PR [#1714](https://github.com/fastapi/sqlmodel/pull/1714) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump prek from 0.2.25 to 0.2.30. PR [#1716](https://github.com/fastapi/sqlmodel/pull/1716) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆️ Update FastAPI version pin to `>=0.103.2` in tests. PR [#1709](https://github.com/fastapi/sqlmodel/pull/1709) by [@YuriiMotov](https://github.com/YuriiMotov).\n* 📌 Pin development Python version to 3.10, for `deploy_docs_status.py`. PR [#1707](https://github.com/fastapi/sqlmodel/pull/1707) by [@tiangolo](https://github.com/tiangolo).\n* ⬆️  Migrate to uv. PR [#1688](https://github.com/fastapi/sqlmodel/pull/1688) by [@DoctorJohn](https://github.com/DoctorJohn).\n* ⬆ Update fastapi requirement from >=0.103.2,<0.126.0 to >=0.103.2,<0.129.0. PR [#1703](https://github.com/fastapi/sqlmodel/pull/1703) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Update tests, remove conditionals for Pydantic v1. PR [#1702](https://github.com/fastapi/sqlmodel/pull/1702) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.31\n\n### Breaking Changes\n\n* ➖ Drop support for Pydantic v1. PR [#1701](https://github.com/fastapi/sqlmodel/pull/1701) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* ⬆ Bump dirty-equals from 0.9.0 to 0.11. PR [#1649](https://github.com/fastapi/sqlmodel/pull/1649) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.7.0 to 9.7.1. PR [#1690](https://github.com/fastapi/sqlmodel/pull/1690) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.20.1 to 0.21.0. PR [#1694](https://github.com/fastapi/sqlmodel/pull/1694) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 📌 Relax `prek` version pin to `>=0.2.24,<1.0.0`. PR [#1698](https://github.com/fastapi/sqlmodel/pull/1698) by [@YuriiMotov](https://github.com/YuriiMotov).\n\n## 0.0.30\n\n### Breaking Changes\n\n* ➖ Drop support for Python 3.8. PR [#1696](https://github.com/fastapi/sqlmodel/pull/1696) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* ➖ Drop support for Python 3.8 in CI and docs. PR [#1695](https://github.com/fastapi/sqlmodel/pull/1695) by [@YuriiMotov](https://github.com/YuriiMotov) and [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* 🔧 Update pre-commit, generate select on pre-commit, use local Ruff. PR [#1697](https://github.com/fastapi/sqlmodel/pull/1697) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump actions/checkout from 5 to 6. PR [#1692](https://github.com/fastapi/sqlmodel/pull/1692) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Add pre-commit workflow. PR [#1684](https://github.com/fastapi/sqlmodel/pull/1684) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ✅ Simplify tests for code examples, one test file for multiple variants. PR [#1664](https://github.com/fastapi/sqlmodel/pull/1664) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1677](https://github.com/fastapi/sqlmodel/pull/1677) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump actions/download-artifact from 6 to 7. PR [#1676](https://github.com/fastapi/sqlmodel/pull/1676) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/cache from 4 to 5. PR [#1673](https://github.com/fastapi/sqlmodel/pull/1673) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump markdown-include-variants from 0.0.5 to 0.0.8. PR [#1674](https://github.com/fastapi/sqlmodel/pull/1674) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/upload-artifact from 5 to 6. PR [#1675](https://github.com/fastapi/sqlmodel/pull/1675) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mypy from 1.18.2 to 1.19.1. PR [#1679](https://github.com/fastapi/sqlmodel/pull/1679) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.20.0 to 0.20.1. PR [#1685](https://github.com/fastapi/sqlmodel/pull/1685) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.8 to 0.14.10. PR [#1681](https://github.com/fastapi/sqlmodel/pull/1681) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.29\n\n### Fixes\n\n* 🐛 Fix `alias` support for Pydantic v2. PR [#1577](https://github.com/fastapi/sqlmodel/pull/1577) by [@ravishan16](https://github.com/ravishan16).\n\n## 0.0.28\n\n### Fixes\n\n* 🐛 Fix `RuntimeError: dictionary changed size during iteration` in `sqlmodel_update()`. PR [#997](https://github.com/fastapi/sqlmodel/pull/997) by [@BartSchuurmans](https://github.com/BartSchuurmans).\n\n### Docs\n\n* 💅 Update CSS to explicitly use emoji font. PR [#1658](https://github.com/fastapi/sqlmodel/pull/1658) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update link to JetBrains Python survey in `features.md`. PR [#1627](https://github.com/fastapi/sqlmodel/pull/1627) by [@sparkiegeek](https://github.com/sparkiegeek).\n* 📝 Fix broken links in docs. PR [#1601](https://github.com/fastapi/sqlmodel/pull/1601) by [@YuriiMotov](https://github.com/YuriiMotov).\n\n### Internal\n\n* 📌 Pin FastAPI in tests to 0.125.0 while dropping support for Python 3.8. PR [#1689](https://github.com/fastapi/sqlmodel/pull/1689) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Configure coverage, error on main tests, don't wait for Smokeshow. PR [#1683](https://github.com/fastapi/sqlmodel/pull/1683) by [@YuriiMotov](https://github.com/YuriiMotov).\n* 👷 Run Smokeshow always, even on test failures. PR [#1682](https://github.com/fastapi/sqlmodel/pull/1682) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ⬆ Bump ruff from 0.14.6 to 0.14.8. PR [#1667](https://github.com/fastapi/sqlmodel/pull/1667) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1662](https://github.com/fastapi/sqlmodel/pull/1662) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump actions/checkout from 5 to 6. PR [#1656](https://github.com/fastapi/sqlmodel/pull/1656) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.5 to 0.14.6. PR [#1652](https://github.com/fastapi/sqlmodel/pull/1652) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1655](https://github.com/fastapi/sqlmodel/pull/1655) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump actions/checkout from 5 to 6. PR [#1651](https://github.com/fastapi/sqlmodel/pull/1651) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 💄 Use font Fira Code to fix display of Rich panels in docs in Windows. PR [#1653](https://github.com/fastapi/sqlmodel/pull/1653) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Upgrade `latest-changes` GitHub Action and pin `actions/checkout@v5`. PR [#1654](https://github.com/fastapi/sqlmodel/pull/1654) by [@svlandeg](https://github.com/svlandeg).\n* 🔧 Upgrade Material for MkDocs and remove insiders. PR [#1650](https://github.com/fastapi/sqlmodel/pull/1650) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump mkdocs-material from 9.6.23 to 9.7.0. PR [#1645](https://github.com/fastapi/sqlmodel/pull/1645) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-macros-plugin from 1.4.1 to 1.5.0. PR [#1647](https://github.com/fastapi/sqlmodel/pull/1647) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.4 to 0.14.5. PR [#1646](https://github.com/fastapi/sqlmodel/pull/1646) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1648](https://github.com/fastapi/sqlmodel/pull/1648) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.14.3 to 0.14.4. PR [#1640](https://github.com/fastapi/sqlmodel/pull/1640) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1642](https://github.com/fastapi/sqlmodel/pull/1642) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump mkdocs-material from 9.6.22 to 9.6.23. PR [#1637](https://github.com/fastapi/sqlmodel/pull/1637) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.2 to 0.14.3. PR [#1633](https://github.com/fastapi/sqlmodel/pull/1633) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1636](https://github.com/fastapi/sqlmodel/pull/1636) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump mkdocs-macros-plugin from 1.4.0 to 1.4.1. PR [#1626](https://github.com/fastapi/sqlmodel/pull/1626) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.1 to 0.14.2. PR [#1616](https://github.com/fastapi/sqlmodel/pull/1616) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1625](https://github.com/fastapi/sqlmodel/pull/1625) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* 🔧 Add PEP-639 license metadata. PR [#1624](https://github.com/fastapi/sqlmodel/pull/1624) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump griffe-typingdoc from 0.2.9 to 0.3.0. PR [#1615](https://github.com/fastapi/sqlmodel/pull/1615) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/upload-artifact from 4 to 5. PR [#1620](https://github.com/fastapi/sqlmodel/pull/1620) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/download-artifact from 5 to 6. PR [#1621](https://github.com/fastapi/sqlmodel/pull/1621) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.14.0 to 0.14.1. PR [#1614](https://github.com/fastapi/sqlmodel/pull/1614) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.13.2 to 0.14.0. PR [#1592](https://github.com/fastapi/sqlmodel/pull/1592) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1605](https://github.com/fastapi/sqlmodel/pull/1605) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump astral-sh/setup-uv from 6 to 7. PR [#1593](https://github.com/fastapi/sqlmodel/pull/1593) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.6.21 to 9.6.22. PR [#1608](https://github.com/fastapi/sqlmodel/pull/1608) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Configure reminder for `waiting` label in `issue-manager`. PR [#1609](https://github.com/fastapi/sqlmodel/pull/1609) by [@YuriiMotov](https://github.com/YuriiMotov).\n* ⬆ Bump typer from 0.19.2 to 0.20.0. PR [#1612](https://github.com/fastapi/sqlmodel/pull/1612) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Remove unused type ignores since SQLAlchemy 2.0.44. PR [#1613](https://github.com/fastapi/sqlmodel/pull/1613) by [@svlandeg](https://github.com/svlandeg).\n\n## 0.0.27\n\n### Upgrades\n\n* ⬆️ Add support for Python 3.14. PR [#1578](https://github.com/fastapi/sqlmodel/pull/1578) by [@svlandeg](https://github.com/svlandeg).\n\n## 0.0.26\n\n### Fixes\n\n* 🐛 Fix attribute handling in `model_dump` for compatibility with the latest Pydantic versions. PR [#1595](https://github.com/fastapi/sqlmodel/pull/1595) by [@spazm](https://github.com/spazm).\n\n### Docs\n\n* 📝 Fix typo in `docs/tutorial/fastapi/simple-hero-api.md`. PR [#1583](https://github.com/fastapi/sqlmodel/pull/1583) by [@kofi-kusi](https://github.com/kofi-kusi).\n\n### Internal\n\n* ⬆ Bump mypy from 1.4.1 to 1.18.2. PR [#1560](https://github.com/fastapi/sqlmodel/pull/1560) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Add test that runs select with 3 or 4 arguments. PR [#1590](https://github.com/fastapi/sqlmodel/pull/1590) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump mkdocs-macros-plugin from 1.3.9 to 1.4.0. PR [#1581](https://github.com/fastapi/sqlmodel/pull/1581) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.6.20 to 9.6.21. PR [#1588](https://github.com/fastapi/sqlmodel/pull/1588) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1584](https://github.com/fastapi/sqlmodel/pull/1584) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump tiangolo/issue-manager from 0.5.1 to 0.6.0. PR [#1589](https://github.com/fastapi/sqlmodel/pull/1589) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Update docs previews comment, single comment, add failure status. PR [#1586](https://github.com/fastapi/sqlmodel/pull/1586) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump markdown-include-variants from 0.0.4 to 0.0.5. PR [#1582](https://github.com/fastapi/sqlmodel/pull/1582) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typing-extensions from 4.13.2 to 4.15.0 for Python 3.9+. PR [#1580](https://github.com/fastapi/sqlmodel/pull/1580) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1571](https://github.com/fastapi/sqlmodel/pull/1571) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump typer from 0.17.4 to 0.19.2. PR [#1573](https://github.com/fastapi/sqlmodel/pull/1573) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.13.0 to 0.13.2. PR [#1576](https://github.com/fastapi/sqlmodel/pull/1576) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 💚 Fix CI test suite for Windows and MacOS. PR [#1307](https://github.com/fastapi/sqlmodel/pull/1307) by [@svlandeg](https://github.com/svlandeg).\n\n## 0.0.25\n\n### Features\n\n* ✨ Add overload for `exec` method to support `insert`, `update`, `delete` statements. PR [#1342](https://github.com/fastapi/sqlmodel/pull/1342) by [@seriaati](https://github.com/seriaati).\n\n### Upgrades\n\n* ⬆️ Drop support for Python 3.7, require Python 3.8 or above. PR [#1316](https://github.com/fastapi/sqlmodel/pull/1316) by [@svlandeg](https://github.com/svlandeg).\n\n### Docs\n\n* ✏️ Fix typos in `docs/tutorial/relationship-attributes/cascade-delete-relationships.md`. PR [#1543](https://github.com/fastapi/sqlmodel/pull/1543) by [@YuriiMotov](https://github.com/YuriiMotov).\n* 🍱 Update SVG files, a single file per diagram, sans-serif fonts. PR [#1373](https://github.com/fastapi/sqlmodel/pull/1373) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Grammar tweak in `docs/tutorial/insert.md`. PR [#1368](https://github.com/fastapi/sqlmodel/pull/1368) by [@brettcannon](https://github.com/brettcannon).\n* 📝 Update `docs/tutorial/fastapi/relationships.md`. PR [#1365](https://github.com/fastapi/sqlmodel/pull/1365) by [@Foxerine](https://github.com/Foxerine).\n* ✏️ Tweak the grammar in `docs/learn/index.md`. PR [#1363](https://github.com/fastapi/sqlmodel/pull/1363) by [@brettcannon](https://github.com/brettcannon).\n* 📝 Update all docs references to `Optional` to use the new syntax in Python 3.10, e.g. `int | None`. PR [#1351](https://github.com/fastapi/sqlmodel/pull/1351) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update install and usage with FastAPI CLI in FastAPI tutorial. PR [#1350](https://github.com/fastapi/sqlmodel/pull/1350) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update FastAPI tutorial docs to use the new `model.sqlmodel_update()` instead of old `setattr()`. PR [#1117](https://github.com/fastapi/sqlmodel/pull/1117) by [@jpizquierdo](https://github.com/jpizquierdo).\n* ✏️ Update `docs/virtual-environments.md`. PR [#1321](https://github.com/fastapi/sqlmodel/pull/1321) by [@sylvainHellin](https://github.com/sylvainHellin).\n\n### Internal\n\n* ⬆ Bump griffe-typingdoc from 0.2.8 to 0.2.9. PR [#1553](https://github.com/fastapi/sqlmodel/pull/1553) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.6.17 to 9.6.20. PR [#1565](https://github.com/fastapi/sqlmodel/pull/1565) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/setup-python from 5 to 6. PR [#1551](https://github.com/fastapi/sqlmodel/pull/1551) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.12.12 to 0.13.0. PR [#1559](https://github.com/fastapi/sqlmodel/pull/1559) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1564](https://github.com/fastapi/sqlmodel/pull/1564) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump actions/labeler from 5 to 6. PR [#1549](https://github.com/fastapi/sqlmodel/pull/1549) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1556](https://github.com/fastapi/sqlmodel/pull/1556) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump typer from 0.17.3 to 0.17.4. PR [#1554](https://github.com/fastapi/sqlmodel/pull/1554) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1546](https://github.com/fastapi/sqlmodel/pull/1546) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.12.10 to 0.12.12. PR [#1548](https://github.com/fastapi/sqlmodel/pull/1548) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.16.1 to 0.17.3. PR [#1547](https://github.com/fastapi/sqlmodel/pull/1547) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pypa/gh-action-pypi-publish from 1.12.4 to 1.13.0. PR [#1550](https://github.com/fastapi/sqlmodel/pull/1550) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Detect and label merge conflicts on PRs automatically. PR [#1552](https://github.com/fastapi/sqlmodel/pull/1552) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump ruff from 0.12.9 to 0.12.10. PR [#1532](https://github.com/fastapi/sqlmodel/pull/1532) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1534](https://github.com/fastapi/sqlmodel/pull/1534) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump typer from 0.16.0 to 0.16.1. PR [#1531](https://github.com/fastapi/sqlmodel/pull/1531) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/download-artifact from 4 to 5. PR [#1451](https://github.com/fastapi/sqlmodel/pull/1451) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/checkout from 4 to 5. PR [#1488](https://github.com/fastapi/sqlmodel/pull/1488) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1479](https://github.com/fastapi/sqlmodel/pull/1479) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump mkdocs-macros-plugin from 1.3.7 to 1.3.9. PR [#1507](https://github.com/fastapi/sqlmodel/pull/1507) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.12.7 to 0.12.9. PR [#1521](https://github.com/fastapi/sqlmodel/pull/1521) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.6.16 to 9.6.17. PR [#1528](https://github.com/fastapi/sqlmodel/pull/1528) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1444](https://github.com/fastapi/sqlmodel/pull/1444) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump mkdocs-material from 9.6.15 to 9.6.16. PR [#1446](https://github.com/fastapi/sqlmodel/pull/1446) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.12.4 to 0.12.7. PR [#1447](https://github.com/fastapi/sqlmodel/pull/1447) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump tiangolo/latest-changes from 0.3.2 to 0.4.0. PR [#1448](https://github.com/fastapi/sqlmodel/pull/1448) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1437](https://github.com/fastapi/sqlmodel/pull/1437) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.12.3 to 0.12.4. PR [#1436](https://github.com/fastapi/sqlmodel/pull/1436) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1428](https://github.com/fastapi/sqlmodel/pull/1428) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.12.2 to 0.12.3. PR [#1432](https://github.com/fastapi/sqlmodel/pull/1432) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1418](https://github.com/fastapi/sqlmodel/pull/1418) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump pillow from 11.2.1 to 11.3.0. PR [#1423](https://github.com/fastapi/sqlmodel/pull/1423) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocs-material from 9.6.14 to 9.6.15. PR [#1424](https://github.com/fastapi/sqlmodel/pull/1424) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.12.0 to 0.12.2. PR [#1425](https://github.com/fastapi/sqlmodel/pull/1425) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1374](https://github.com/fastapi/sqlmodel/pull/1374) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.11.13 to 0.12.0. PR [#1403](https://github.com/fastapi/sqlmodel/pull/1403) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Simplify tests for `tests/test_tutorial/test_code_structure/test_tutorial001.py`, one test file for multiple variants. PR [#1408](https://github.com/fastapi/sqlmodel/pull/1408) by [@tiangolo](https://github.com/tiangolo).\n* ✅ Simplify tests setup, one test file for multiple source variants. PR [#1407](https://github.com/fastapi/sqlmodel/pull/1407) by [@tiangolo](https://github.com/tiangolo).\n* ✅ Refactor tests to use autouse `clear_sqlmodel`. PR [#1406](https://github.com/fastapi/sqlmodel/pull/1406) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump mkdocs-material from 9.5.18 to 9.6.14. PR [#1378](https://github.com/fastapi/sqlmodel/pull/1378) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.15.3 to 0.16.0. PR [#1393](https://github.com/fastapi/sqlmodel/pull/1393) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump cairosvg from 2.7.1 to 2.8.2. PR [#1383](https://github.com/fastapi/sqlmodel/pull/1383) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump ruff from 0.11.7 to 0.11.13. PR [#1397](https://github.com/fastapi/sqlmodel/pull/1397) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Remove Google Analytics. PR [#1386](https://github.com/fastapi/sqlmodel/pull/1386) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump mkdocs-macros-plugin from 1.0.5 to 1.3.7. PR [#1354](https://github.com/fastapi/sqlmodel/pull/1354) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump griffe-typingdoc from 0.2.5 to 0.2.8. PR [#1359](https://github.com/fastapi/sqlmodel/pull/1359) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update pre-commit requirement from <4.0.0,>=2.17.0 to >=2.17.0,<5.0.0. PR [#1360](https://github.com/fastapi/sqlmodel/pull/1360) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pillow from 11.0.0 to 11.2.1. PR [#1361](https://github.com/fastapi/sqlmodel/pull/1361) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1367](https://github.com/fastapi/sqlmodel/pull/1367) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.9.6 to 0.11.7. PR [#1355](https://github.com/fastapi/sqlmodel/pull/1355) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1353](https://github.com/fastapi/sqlmodel/pull/1353) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump typing-extensions from 4.12.2 to 4.13.2. PR [#1356](https://github.com/fastapi/sqlmodel/pull/1356) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump typer from 0.15.2 to 0.15.3. PR [#1357](https://github.com/fastapi/sqlmodel/pull/1357) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1339](https://github.com/fastapi/sqlmodel/pull/1339) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump typer from 0.12.3 to 0.15.2. PR [#1325](https://github.com/fastapi/sqlmodel/pull/1325) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump httpx from 0.24.1 to 0.28.1. PR [#1238](https://github.com/fastapi/sqlmodel/pull/1238) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump astral-sh/setup-uv from 5 to 6. PR [#1348](https://github.com/fastapi/sqlmodel/pull/1348) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update pytest requirement from <8.0.0,>=7.0.1 to >=7.0.1,<9.0.0. PR [#1022](https://github.com/fastapi/sqlmodel/pull/1022) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ♻️ Update `tests/test_select_gen.py`, pass environment variables, needed for NixOS nixpkgs. PR [#969](https://github.com/fastapi/sqlmodel/pull/969) by [@pbsds](https://github.com/pbsds).\n* 💚 Fix linting in CI. PR [#1340](https://github.com/fastapi/sqlmodel/pull/1340) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1327](https://github.com/fastapi/sqlmodel/pull/1327) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump jinja2 from 3.1.4 to 3.1.6. PR [#1317](https://github.com/fastapi/sqlmodel/pull/1317) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1319](https://github.com/fastapi/sqlmodel/pull/1319) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n\n## 0.0.24\n\n### Upgrades\n\n* ⬆️ Add support for Python 3.13. PR [#1289](https://github.com/fastapi/sqlmodel/pull/1289) by [@svlandeg](https://github.com/svlandeg).\n\n### Internal\n\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1114](https://github.com/fastapi/sqlmodel/pull/1114) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.6.2 to 0.9.6. PR [#1294](https://github.com/fastapi/sqlmodel/pull/1294) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.23\n\n### Fixes\n\n* 🐛 Fix type annotation in `Field` constructor. PR [#1304](https://github.com/fastapi/sqlmodel/pull/1304) by [@AlanBogarin](https://github.com/AlanBogarin).\n* 🐛 Fix Pydantic version check for version 2.10.x onwards. PR [#1255](https://github.com/fastapi/sqlmodel/pull/1255) by [@asiunov](https://github.com/asiunov).\n\n### Refactors\n\n* 🚨 Fix types for new Pydantic. PR [#1131](https://github.com/fastapi/sqlmodel/pull/1131) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* 🩺 Take the GH badge only from pushes to the `main` branch. PR [#1291](https://github.com/fastapi/sqlmodel/pull/1291) by [@svlandeg](https://github.com/svlandeg).\n* 📝 Update documentation to refer to `list` instead of `List`. PR [#1147](https://github.com/fastapi/sqlmodel/pull/1147) by [@bubbletroubles](https://github.com/bubbletroubles).\n* ✏️ Fix typo in `databases.md`. PR [#1113](https://github.com/fastapi/sqlmodel/pull/1113) by [@radi-dev](https://github.com/radi-dev).\n* ✏️ Fix typo in `docs/tutorial/create-db-and-table.md`. PR [#1252](https://github.com/fastapi/sqlmodel/pull/1252) by [@ArianHamdi](https://github.com/ArianHamdi).\n* ✏️ Fix typo in `insert.md`. PR [#1256](https://github.com/fastapi/sqlmodel/pull/1256) by [@Noushadaliam](https://github.com/Noushadaliam).\n* 📝 Update markdown includes format. PR [#1254](https://github.com/fastapi/sqlmodel/pull/1254) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update fenced code in Decimal docs for consistency. PR [#1251](https://github.com/fastapi/sqlmodel/pull/1251) by [@tiangolo](https://github.com/tiangolo).\n* ✏️ Fix typo in the release notes of v0.0.22. PR [#1195](https://github.com/fastapi/sqlmodel/pull/1195) by [@PipeKnight](https://github.com/PipeKnight).\n* 📝 Update includes for `docs/advanced/uuid.md`. PR [#1151](https://github.com/fastapi/sqlmodel/pull/1151) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update includes for `docs/tutorial/create-db-and-table.md`. PR [#1149](https://github.com/fastapi/sqlmodel/pull/1149) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Fix internal links in docs. PR [#1148](https://github.com/fastapi/sqlmodel/pull/1148) by [@tiangolo](https://github.com/tiangolo).\n* ✏️ Fix typo in documentation. PR [#1106](https://github.com/fastapi/sqlmodel/pull/1106) by [@Solipsistmonkey](https://github.com/Solipsistmonkey).\n* 📝 Remove highlights in `indexes.md` . PR [#1100](https://github.com/fastapi/sqlmodel/pull/1100) by [@alejsdev](https://github.com/alejsdev).\n\n### Internal\n\n* ⬆ Bump pypa/gh-action-pypi-publish from 1.12.3 to 1.12.4. PR [#1277](https://github.com/fastapi/sqlmodel/pull/1277) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 💚 Fix CI test suite for Python 3.7. PR [#1309](https://github.com/fastapi/sqlmodel/pull/1309) by [@svlandeg](https://github.com/svlandeg).\n* 👷 Revert \"Add Codecov to CI, Smokeshow/Cloudflare has been flaky lately (#1303)\". PR [#1306](https://github.com/fastapi/sqlmodel/pull/1306) by [@svlandeg](https://github.com/svlandeg).\n*  👷 Add Codecov to CI, Smokeshow/Cloudflare has been flaky lately. PR [#1303](https://github.com/fastapi/sqlmodel/pull/1303) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add retries to Smokeshow. PR [#1302](https://github.com/fastapi/sqlmodel/pull/1302) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ Bump astral-sh/setup-uv from 4 to 5. PR [#1249](https://github.com/fastapi/sqlmodel/pull/1249) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pillow from 10.3.0 to 11.0.0. PR [#1139](https://github.com/fastapi/sqlmodel/pull/1139) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pypa/gh-action-pypi-publish from 1.9.0 to 1.12.3. PR [#1240](https://github.com/fastapi/sqlmodel/pull/1240) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump astral-sh/setup-uv from 3 to 4. PR [#1225](https://github.com/fastapi/sqlmodel/pull/1225) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump tiangolo/latest-changes from 0.3.1 to 0.3.2. PR [#1207](https://github.com/fastapi/sqlmodel/pull/1207) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔨 Update docs previews script. PR [#1236](https://github.com/fastapi/sqlmodel/pull/1236) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update build-docs filter paths. PR [#1235](https://github.com/fastapi/sqlmodel/pull/1235) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update team members. PR [#1234](https://github.com/fastapi/sqlmodel/pull/1234) by [@tiangolo](https://github.com/tiangolo).\n* ⬆️ Upgrade markdown-include-variants to version 0.0.3. PR [#1152](https://github.com/fastapi/sqlmodel/pull/1152) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update issue manager workflow. PR [#1137](https://github.com/fastapi/sqlmodel/pull/1137) by [@alejsdev](https://github.com/alejsdev).\n* 👷 Fix smokeshow, checkout files on CI. PR [#1136](https://github.com/fastapi/sqlmodel/pull/1136) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Use uv in CI. PR [#1135](https://github.com/fastapi/sqlmodel/pull/1135) by [@tiangolo](https://github.com/tiangolo).\n* ➕ Add docs dependency markdown-include-variants. PR [#1129](https://github.com/fastapi/sqlmodel/pull/1129) by [@tiangolo](https://github.com/tiangolo).\n* 🔨 Update script to standardize format. PR [#1130](https://github.com/fastapi/sqlmodel/pull/1130) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update `labeler.yml`. PR [#1128](https://github.com/fastapi/sqlmodel/pull/1128) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update worfkow deploy-docs-notify URL. PR [#1126](https://github.com/fastapi/sqlmodel/pull/1126) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Upgrade Cloudflare GitHub Action. PR [#1124](https://github.com/fastapi/sqlmodel/pull/1124) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1097](https://github.com/fastapi/sqlmodel/pull/1097) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump tiangolo/issue-manager from 0.5.0 to 0.5.1. PR [#1107](https://github.com/fastapi/sqlmodel/pull/1107) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Update `issue-manager.yml`. PR [#1103](https://github.com/fastapi/sqlmodel/pull/1103) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Fix coverage processing in CI, one name per matrix run. PR [#1104](https://github.com/fastapi/sqlmodel/pull/1104) by [@tiangolo](https://github.com/tiangolo).\n* 💚 Set `include-hidden-files` to `True` when using the `upload-artifact` GH action. PR [#1098](https://github.com/fastapi/sqlmodel/pull/1098) by [@svlandeg](https://github.com/svlandeg).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1088](https://github.com/fastapi/sqlmodel/pull/1088) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n\n## 0.0.22\n\n### Fixes\n\n* 🐛 Fix support for types with `Optional[Annotated[x, f()]]`, e.g. `id: Optional[pydantic.UUID4]`. PR [#1093](https://github.com/fastapi/sqlmodel/pull/1093) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* ✏️ Fix a typo in `docs/virtual-environments.md`. PR [#1085](https://github.com/fastapi/sqlmodel/pull/1085) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Add docs for virtual environments and environment variables, update contributing. PR [#1082](https://github.com/fastapi/sqlmodel/pull/1082) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Add docs about repo management and team. PR [#1059](https://github.com/tiangolo/sqlmodel/pull/1059) by [@tiangolo](https://github.com/tiangolo).\n* ✏️ Fix typo in `cascade_delete` docs. PR [#1030](https://github.com/tiangolo/sqlmodel/pull/1030) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* ✅ Refactor test_enums to make them independent of previous imports. PR [#1095](https://github.com/fastapi/sqlmodel/pull/1095) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update `latest-changes` GitHub Action. PR [#1087](https://github.com/fastapi/sqlmodel/pull/1087) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#1028](https://github.com/fastapi/sqlmodel/pull/1028) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump ruff from 0.4.7 to 0.6.2. PR [#1081](https://github.com/fastapi/sqlmodel/pull/1081) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Update lint script. PR [#1084](https://github.com/fastapi/sqlmodel/pull/1084) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update Python version for coverage. PR [#1083](https://github.com/fastapi/sqlmodel/pull/1083) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update coverage config files. PR [#1077](https://github.com/fastapi/sqlmodel/pull/1077) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Add URLs to `pyproject.toml`, show up in PyPI. PR [#1074](https://github.com/fastapi/sqlmodel/pull/1074) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Do not sync labels as it overrides manually added labels. PR [#1073](https://github.com/fastapi/sqlmodel/pull/1073) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update configs for GitHub Action labeler, to add only one label. PR [#1072](https://github.com/fastapi/sqlmodel/pull/1072) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update labeler GitHub Actions permissions and dependencies. PR [#1071](https://github.com/fastapi/sqlmodel/pull/1071) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add GitHub Action label-checker. PR [#1069](https://github.com/fastapi/sqlmodel/pull/1069) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add GitHub Action labeler. PR [#1068](https://github.com/fastapi/sqlmodel/pull/1068) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update GitHub Action add-to-project. PR [#1067](https://github.com/fastapi/sqlmodel/pull/1067) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add GitHub Action add-to-project. PR [#1066](https://github.com/fastapi/sqlmodel/pull/1066) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update admonitions in annotations. PR [#1065](https://github.com/fastapi/sqlmodel/pull/1065) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update links from github.com/tiangolo/sqlmodel to github.com/fastapi/sqlmodel. PR [#1064](https://github.com/fastapi/sqlmodel/pull/1064) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update members. PR [#1063](https://github.com/tiangolo/sqlmodel/pull/1063) by [@tiangolo](https://github.com/tiangolo).\n* 💄 Add dark-mode logo. PR [#1061](https://github.com/tiangolo/sqlmodel/pull/1061) by [@tiangolo](https://github.com/tiangolo).\n* 🔨 Update docs.py script to enable dirty reload conditionally. PR [#1060](https://github.com/tiangolo/sqlmodel/pull/1060) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update MkDocs previews. PR [#1058](https://github.com/tiangolo/sqlmodel/pull/1058) by [@tiangolo](https://github.com/tiangolo).\n* 💄 Update Termynal line-height. PR [#1057](https://github.com/tiangolo/sqlmodel/pull/1057) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Upgrade build docs configs. PR [#1047](https://github.com/tiangolo/sqlmodel/pull/1047) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add alls-green for test-redistribute. PR [#1055](https://github.com/tiangolo/sqlmodel/pull/1055) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update docs-previews to handle no docs changes. PR [#1056](https://github.com/tiangolo/sqlmodel/pull/1056) by [@tiangolo](https://github.com/tiangolo).\n* 👷🏻 Show docs deployment status and preview URLs in comment. PR [#1054](https://github.com/tiangolo/sqlmodel/pull/1054) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Enable auto dark mode. PR [#1046](https://github.com/tiangolo/sqlmodel/pull/1046) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update issue-manager. PR [#1045](https://github.com/tiangolo/sqlmodel/pull/1045) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update issue-manager.yml GitHub Action permissions. PR [#1040](https://github.com/tiangolo/sqlmodel/pull/1040) by [@tiangolo](https://github.com/tiangolo).\n* ♻️ Refactor Deploy Docs GitHub Action to be a script and update token preparing for org. PR [#1039](https://github.com/tiangolo/sqlmodel/pull/1039) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.21\n\n### Features\n\n* ✨ Add support for cascade delete relationships: `cascade_delete`, `ondelete`, and `passive_deletes`. Initial PR [#983](https://github.com/tiangolo/sqlmodel/pull/983) by [@estebanx64](https://github.com/estebanx64).\n  * New docs at: [Cascade Delete Relationships](https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/).\n\n### Docs\n\n* 📝 Update docs . PR [#1003](https://github.com/tiangolo/sqlmodel/pull/1003) by [@alejsdev](https://github.com/alejsdev).\n\n### Internal\n\n* ⬆ Bump actions/cache from 3 to 4. PR [#783](https://github.com/tiangolo/sqlmodel/pull/783) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump cairosvg from 2.7.0 to 2.7.1. PR [#919](https://github.com/tiangolo/sqlmodel/pull/919) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump jinja2 from 3.1.3 to 3.1.4. PR [#974](https://github.com/tiangolo/sqlmodel/pull/974) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump pypa/gh-action-pypi-publish from 1.8.11 to 1.9.0. PR [#987](https://github.com/tiangolo/sqlmodel/pull/987) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump mkdocstrings[python] from 0.23.0 to 0.25.1. PR [#927](https://github.com/tiangolo/sqlmodel/pull/927) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump dorny/paths-filter from 2 to 3. PR [#972](https://github.com/tiangolo/sqlmodel/pull/972) by [@dependabot[bot]](https://github.com/apps/dependabot).\n\n## 0.0.20\n\n### Features\n\n* ✨ Add official UUID support, docs and tests, internally using new SQLAlchemy 2.0 types. Initial PR [#992](https://github.com/tiangolo/sqlmodel/pull/992) by [@estebanx64](https://github.com/estebanx64).\n  * New docs in the [Advanced User Guide: UUID (Universally Unique Identifiers)](https://sqlmodel.tiangolo.com/advanced/uuid/).\n\n### Docs\n\n* ✏️ Fix internal link in `docs/tutorial/create-db-and-table.md`. PR [#911](https://github.com/tiangolo/sqlmodel/pull/911) by [@tfpgh](https://github.com/tfpgh).\n* ✏️ Add missing step in `create-db-and-table-with-db-browser.md`. PR [#976](https://github.com/tiangolo/sqlmodel/pull/976) by [@alejsdev](https://github.com/alejsdev).\n* ✏️ Fix typo in `docs/tutorial`. PR [#943](https://github.com/tiangolo/sqlmodel/pull/943) by [@luco17](https://github.com/luco17).\n* ✏️ Fix typo in `sqlmodel/_compat.py`. PR [#950](https://github.com/tiangolo/sqlmodel/pull/950) by [@Highfire1](https://github.com/Highfire1).\n* ✏️ Update pip installation command in tutorial. PR [#975](https://github.com/tiangolo/sqlmodel/pull/975) by [@alejsdev](https://github.com/alejsdev).\n* ✏️ Fix typo in `docs/tutorial/relationship-attributes/index.md`. PR [#880](https://github.com/tiangolo/sqlmodel/pull/880) by [@UncleGoogle](https://github.com/UncleGoogle).\n\n### Internal\n\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#979](https://github.com/tiangolo/sqlmodel/pull/979) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* 🔨 Update docs Termynal scripts to not include line nums for local dev. PR [#1018](https://github.com/tiangolo/sqlmodel/pull/1018) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.19\n\n### Fixes\n\n* 🐛 Fix pydantic `EmailStr` support and `max_length` in several String subclasses. PR [#966](https://github.com/tiangolo/sqlmodel/pull/966) by [@estebanx64](https://github.com/estebanx64).\n* 🐛 Fix set varchar limit when `max_length` is set on Pydantic models using Pydantic v2. PR [#963](https://github.com/tiangolo/sqlmodel/pull/963) by [@estebanx64](https://github.com/estebanx64).\n\n### Refactors\n\n* ♻️ Refactor generate select template to isolate templated code to the minimum. PR [#967](https://github.com/tiangolo/sqlmodel/pull/967) by [@tiangolo](https://github.com/tiangolo).\n\n### Upgrades\n\n* ⬆️ Update minimum SQLAlchemy version to 2.0.14 as that one includes `TryCast` used internally. PR [#964](https://github.com/tiangolo/sqlmodel/pull/964) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* ✏️ Fix broken link to `@dataclass_transform` (now PEP 681) in `docs/features.md`. PR [#753](https://github.com/tiangolo/sqlmodel/pull/753) by [@soof-golan](https://github.com/soof-golan).\n\n### Internal\n\n* ⬆️ Upgrade Ruff and Black. PR [#968](https://github.com/tiangolo/sqlmodel/pull/968) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump tiangolo/issue-manager from 0.4.1 to 0.5.0. PR [#922](https://github.com/tiangolo/sqlmodel/pull/922) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 📌 Pin typing-extensions in tests for compatiblity with Python 3.8, dirty-equals, Pydantic. PR [#965](https://github.com/tiangolo/sqlmodel/pull/965) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update GitHub Actions to download and upload artifacts. PR [#936](https://github.com/tiangolo/sqlmodel/pull/936) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Tweak CI for test-redistribute, add needed env vars for slim. PR [#929](https://github.com/tiangolo/sqlmodel/pull/929) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.18\n\n### Internal\n\n* ✨ Add `sqlmodel-slim` setup. PR [#916](https://github.com/tiangolo/sqlmodel/pull/916) by [@tiangolo](https://github.com/tiangolo).\n\nIn the future SQLModel will include the standard default recommended packages, and `sqlmodel-slim` will come without those recommended standard packages and with a group of optional dependencies `sqlmodel-slim[standard]`, equivalent to `sqlmodel`, for those that want to opt out of those packages.\n\n* 🔧 Re-enable MkDocs Material Social plugin. PR [#915](https://github.com/tiangolo/sqlmodel/pull/915) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.17\n\n### Refactors\n\n* ♻️ Refactor types to properly support Pydantic 2.7. PR [#913](https://github.com/tiangolo/sqlmodel/pull/913) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* 📝 Update ModelRead to ModelPublic documentation and examples. PR [#885](https://github.com/tiangolo/sqlmodel/pull/885) by [@estebanx64](https://github.com/estebanx64).\n* ✨ Add source examples for Python 3.10 and 3.9 with updated syntax. PR [#842](https://github.com/tiangolo/sqlmodel/pull/842) by [@tiangolo](https://github.com/tiangolo) and [@estebanx64](https://github.com/estebanx64).\n\n### Internal\n\n* ⬆ Bump actions/setup-python from 4 to 5. PR [#733](https://github.com/tiangolo/sqlmodel/pull/733) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔨 Update internal scripts and remove unused ones. PR [#914](https://github.com/tiangolo/sqlmodel/pull/914) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Migrate from Poetry to PDM for the internal build config. PR [#912](https://github.com/tiangolo/sqlmodel/pull/912) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update MkDocs, disable cards while I can upgrade to the latest MkDocs Material, that fixes an issue with social cards. PR [#888](https://github.com/tiangolo/sqlmodel/pull/888) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add cron to run test once a week on monday. PR [#869](https://github.com/tiangolo/sqlmodel/pull/869) by [@estebanx64](https://github.com/estebanx64).\n* ⬆️ Upgrade Ruff version and configs. PR [#859](https://github.com/tiangolo/sqlmodel/pull/859) by [@tiangolo](https://github.com/tiangolo).\n* 🔥 Remove Jina QA Bot as it has been discontinued. PR [#840](https://github.com/tiangolo/sqlmodel/pull/840) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.16\n\n### Features\n\n* ✨ Add new method `.sqlmodel_update()` to update models in place, including an `update` parameter for extra data. And fix implementation for the (now documented) `update` parameter for `.model_validate()`. PR [#804](https://github.com/tiangolo/sqlmodel/pull/804) by [@tiangolo](https://github.com/tiangolo).\n    * Updated docs: [Update Data with FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/update/).\n    * New docs: [Update with Extra Data (Hashed Passwords) with FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/update-extra-data/).\n\n## 0.0.15\n\n### Fixes\n\n* 🐛 Fix class initialization compatibility with Pydantic and SQLModel, fixing errors revealed by the latest Pydantic. PR [#807](https://github.com/tiangolo/sqlmodel/pull/807) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* ⬆ Bump tiangolo/issue-manager from 0.4.0 to 0.4.1. PR [#775](https://github.com/tiangolo/sqlmodel/pull/775) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Fix GitHub Actions build docs filter paths for GitHub workflows. PR [#738](https://github.com/tiangolo/sqlmodel/pull/738) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.14\n\n### Features\n\n* ✨ Add support for Pydantic v2 (while keeping support for v1 if v2 is not available). PR [#722](https://github.com/tiangolo/sqlmodel/pull/722) by [@tiangolo](https://github.com/tiangolo) including initial work in PR [#699](https://github.com/tiangolo/sqlmodel/pull/699) by [@AntonDeMeester](https://github.com/AntonDeMeester).\n\n## 0.0.13\n\n### Fixes\n\n* ♻️ Refactor type generation of selects re-order to prioritize models to optimize editor support. PR [#718](https://github.com/tiangolo/sqlmodel/pull/718) by [@tiangolo](https://github.com/tiangolo).\n\n### Refactors\n\n* 🔇 Do not raise deprecation warnings for execute as it's automatically used internally. PR [#716](https://github.com/tiangolo/sqlmodel/pull/716) by [@tiangolo](https://github.com/tiangolo).\n* ✅ Move OpenAPI tests inline to simplify updating them with Pydantic v2. PR [#709](https://github.com/tiangolo/sqlmodel/pull/709) by [@tiangolo](https://github.com/tiangolo).\n\n### Upgrades\n\n* ⬆️ Add support for Python 3.11 and Python 3.12. PR [#710](https://github.com/tiangolo/sqlmodel/pull/710) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* ✏️ Fix typo, simplify single quote/apostrophe character in \"Sister Margaret's\" everywhere in the docs. PR [#721](https://github.com/tiangolo/sqlmodel/pull/721) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update docs for Decimal, use proper types. PR [#719](https://github.com/tiangolo/sqlmodel/pull/719) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Add source examples for Python 3.9 and 3.10. PR [#715](https://github.com/tiangolo/sqlmodel/pull/715) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* 🙈 Update gitignore, include all coverage files. PR [#711](https://github.com/tiangolo/sqlmodel/pull/711) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update config with new pymdown extensions. PR [#712](https://github.com/tiangolo/sqlmodel/pull/712) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update docs build setup, add support for sponsors, add sponsor GOVCERT.LU. PR [#720](https://github.com/tiangolo/sqlmodel/pull/720) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#697](https://github.com/tiangolo/sqlmodel/pull/697) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* 🔧 Show line numbers in docs during local development. PR [#714](https://github.com/tiangolo/sqlmodel/pull/714) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Update details syntax with new pymdown extensions format. PR [#713](https://github.com/tiangolo/sqlmodel/pull/713) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.12\n\n### Features\n\n* ✨ Upgrade SQLAlchemy to 2.0. PR [#700](https://github.com/tiangolo/sqlmodel/pull/700) by [@tiangolo](https://github.com/tiangolo) including initial work in PR [#563](https://github.com/tiangolo/sqlmodel/pull/563) by [@farahats9](https://github.com/farahats9).\n\n### Internal\n\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#686](https://github.com/tiangolo/sqlmodel/pull/686) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* 👷 Upgrade latest-changes GitHub Action. PR [#693](https://github.com/tiangolo/sqlmodel/pull/693) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.11\n\n### Features\n\n* ✨ Add support for passing a custom SQLAlchemy type to `Field()` with `sa_type`. PR [#505](https://github.com/tiangolo/sqlmodel/pull/505) by [@maru0123-2004](https://github.com/maru0123-2004).\n    * You might consider this a breaking change if you were using an incompatible combination of arguments, those arguments were not taking effect and now you will have a type error and runtime error telling you that.\n* ✨ Do not allow invalid combinations of field parameters for columns and relationships, `sa_column` excludes `sa_column_args`, `primary_key`, `nullable`, etc. PR [#681](https://github.com/tiangolo/sqlmodel/pull/681) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* 🎨 Update inline source examples, hide `#` in annotations (from MkDocs Material). PR [#677](https://github.com/tiangolo/sqlmodel/pull/677) by [@Matthieu-LAURENT39](https://github.com/Matthieu-LAURENT39).\n\n### Internal\n\n* ⬆ Update coverage requirement from ^6.2 to >=6.2,<8.0. PR [#663](https://github.com/tiangolo/sqlmodel/pull/663) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update mkdocs-material requirement from 9.1.21 to 9.2.7. PR [#675](https://github.com/tiangolo/sqlmodel/pull/675) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆️ Upgrade mypy manually. PR [#684](https://github.com/tiangolo/sqlmodel/pull/684) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Update black requirement from ^22.10.0 to >=22.10,<24.0. PR [#664](https://github.com/tiangolo/sqlmodel/pull/664) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Update CI to build MkDocs Insiders only when the secrets are available, for Dependabot. PR [#683](https://github.com/tiangolo/sqlmodel/pull/683) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.10\n\n### Features\n\n* ✨ Add support for all `Field` parameters from Pydantic `1.9.0` and above, make Pydantic `1.9.0` the minimum required version. PR [#440](https://github.com/tiangolo/sqlmodel/pull/440) by [@daniil-berg](https://github.com/daniil-berg).\n\n### Internal\n\n* 🔧 Adopt Ruff for formatting. PR [#679](https://github.com/tiangolo/sqlmodel/pull/679) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.9\n\n### Breaking Changes\n\n* 🗑️ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo).\n\n### Features\n\n* ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier).\n\n### Fixes\n\n* 🐛 Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium).\n* 🐛 Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg).\n* 🐛 Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo).\n* 🐛 Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman).\n\n### Upgrades\n\n* ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi).\n* ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg).\n\n### Docs\n\n* 📝 Clarify description of in-memory SQLite database in `docs/tutorial/create-db-and-table.md`. PR [#601](https://github.com/tiangolo/sqlmodel/pull/601) by [@SimonCW](https://github.com/SimonCW).\n* 📝 Tweak wording in `docs/tutorial/fastapi/multiple-models.md`. PR [#674](https://github.com/tiangolo/sqlmodel/pull/674) by [@tiangolo](https://github.com/tiangolo).\n* ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns).\n* 📝 Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew).\n* 📝 Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck).\n* 📝 Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw).\n* 📝 Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF).\n* ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng).\n* 📝 Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP).\n* 📝 Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow).\n* 📝 Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura).\n* 📝 Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo).\n* ✏️ Fix typo in internal function name `get_sqlachemy_type()`. PR [#496](https://github.com/tiangolo/sqlmodel/pull/496) by [@cmarqu](https://github.com/cmarqu).\n* ✏️ Fix typo in docs. PR [#446](https://github.com/tiangolo/sqlmodel/pull/446) by [@davidbrochart](https://github.com/davidbrochart).\n* ✏️ Fix typo in `docs/tutorial/create-db-and-table.md`. PR [#477](https://github.com/tiangolo/sqlmodel/pull/477) by [@FluffyDietEngine](https://github.com/FluffyDietEngine).\n* ✏️ Fix small typos in docs. PR [#481](https://github.com/tiangolo/sqlmodel/pull/481) by [@micuffaro](https://github.com/micuffaro).\n\n### Internal\n\n* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#672](https://github.com/tiangolo/sqlmodel/pull/672) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).\n* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ✅ Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx).\n* ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo).\n* 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo).\n* 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo).\n* 🛠️ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray).\n* 👷 Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo).\n* 👷‍♂️ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo).\n* ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Refactor CI artifact upload/download for docs previews. PR [#514](https://github.com/tiangolo/sqlmodel/pull/514) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump actions/cache from 2 to 3. PR [#497](https://github.com/tiangolo/sqlmodel/pull/497) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump dawidd6/action-download-artifact from 2.24.0 to 2.24.2. PR [#493](https://github.com/tiangolo/sqlmodel/pull/493) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 🔧 Update Smokeshow coverage threshold. PR [#487](https://github.com/tiangolo/sqlmodel/pull/487) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Move from Codecov to Smokeshow. PR [#486](https://github.com/tiangolo/sqlmodel/pull/486) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Bump actions/setup-python from 2 to 4. PR [#411](https://github.com/tiangolo/sqlmodel/pull/411) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update black requirement from ^21.5-beta.1 to ^22.10.0. PR [#460](https://github.com/tiangolo/sqlmodel/pull/460) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ➕ Add extra dev dependencies for MkDocs Material. PR [#485](https://github.com/tiangolo/sqlmodel/pull/485) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Update mypy requirement from 0.930 to 0.971. PR [#380](https://github.com/tiangolo/sqlmodel/pull/380) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update coverage requirement from ^5.5 to ^6.2. PR [#171](https://github.com/tiangolo/sqlmodel/pull/171) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump codecov/codecov-action from 2 to 3. PR [#415](https://github.com/tiangolo/sqlmodel/pull/415) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/upload-artifact from 2 to 3. PR [#412](https://github.com/tiangolo/sqlmodel/pull/412) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update flake8 requirement from ^3.9.2 to ^5.0.4. PR [#396](https://github.com/tiangolo/sqlmodel/pull/396) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Update pytest requirement from ^6.2.4 to ^7.0.1. PR [#242](https://github.com/tiangolo/sqlmodel/pull/242) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump actions/checkout from 2 to 3.1.0. PR [#458](https://github.com/tiangolo/sqlmodel/pull/458) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.24.0. PR [#470](https://github.com/tiangolo/sqlmodel/pull/470) by [@dependabot[bot]](https://github.com/apps/dependabot).\n* 👷 Update Dependabot config. PR [#484](https://github.com/tiangolo/sqlmodel/pull/484) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.8\n\n### Fixes\n\n* 🐛 Fix auto detecting and setting `nullable`, allowing overrides in field. PR [#423](https://github.com/tiangolo/sqlmodel/pull/423) by [@JonasKs](https://github.com/JonasKs) and [@br-follow](https://github.com/br-follow).\n* ♻️ Update `expresion.py`, sync from Jinja2 template, implement `inherit_cache` to solve errors like: `SAWarning: Class SelectOfScalar will not make use of SQL compilation caching`. PR [#422](https://github.com/tiangolo/sqlmodel/pull/422) by [@tiangolo](https://github.com/tiangolo).\n\n### Docs\n\n* 📝 Adjust and clarify docs for `docs/tutorial/create-db-and-table.md`. PR [#426](https://github.com/tiangolo/sqlmodel/pull/426) by [@tiangolo](https://github.com/tiangolo).\n* ✏ Fix typo in `docs/tutorial/connect/remove-data-connections.md`. PR [#421](https://github.com/tiangolo/sqlmodel/pull/421) by [@VerdantFox](https://github.com/VerdantFox).\n\n## 0.0.7\n\n### Features\n\n* ✨ Allow setting `unique` in `Field()` for a column. PR [#83](https://github.com/tiangolo/sqlmodel/pull/83) by [@raphaelgibson](https://github.com/raphaelgibson).\n* ✨ Update GUID handling to use stdlib `UUID.hex` instead of an `int`. PR [#26](https://github.com/tiangolo/sqlmodel/pull/26) by [@andrewbolster](https://github.com/andrewbolster).\n* ✨ Raise an exception when using a Pydantic field type with no matching SQLAlchemy type. PR [#18](https://github.com/tiangolo/sqlmodel/pull/18) by [@elben10](https://github.com/elben10).\n* ⬆ Upgrade constrain for SQLAlchemy = \">=1.4.17,<=1.4.41\". PR [#371](https://github.com/tiangolo/sqlmodel/pull/371) by [@RobertRosca](https://github.com/RobertRosca).\n* ✨ Add new `Session.get()` parameter `execution_options`. PR [#302](https://github.com/tiangolo/sqlmodel/pull/302) by [@tiangolo](https://github.com/tiangolo).\n\n### Fixes\n\n* 🐛 Fix type annotations for `Model.parse_obj()`, and `Model.validate()`. PR [#321](https://github.com/tiangolo/sqlmodel/pull/321) by [@phi-friday](https://github.com/phi-friday).\n* 🐛 Fix `Select` and `SelectOfScalar` to inherit cache to avoid warning: `SAWarning: Class SelectOfScalar will not make use of SQL compilation caching`. PR [#234](https://github.com/tiangolo/sqlmodel/pull/234) by [@rabinadk1](https://github.com/rabinadk1).\n* 🐛 Fix handling validators for non-default values. PR [#253](https://github.com/tiangolo/sqlmodel/pull/253) by [@byrman](https://github.com/byrman).\n* 🐛 Fix fields marked as \"set\" in models. PR [#117](https://github.com/tiangolo/sqlmodel/pull/117) by [@statt8900](https://github.com/statt8900).\n* 🐛 Fix Enum handling in SQLAlchemy. PR [#165](https://github.com/tiangolo/sqlmodel/pull/165) by [@chriswhite199](https://github.com/chriswhite199).\n* 🐛 Fix setting nullable property of Fields that don't accept `None`. PR [#79](https://github.com/tiangolo/sqlmodel/pull/79) by [@van51](https://github.com/van51).\n* 🐛 Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#322](https://github.com/tiangolo/sqlmodel/pull/322) by [@byrman](https://github.com/byrman).\n\n### Docs\n\n* 📝 Update docs for models for updating, `id` should not be updatable. PR [#335](https://github.com/tiangolo/sqlmodel/pull/335) by [@kurtportelli](https://github.com/kurtportelli).\n* ✏ Fix broken variable/typo in docs for Read Relationships, `hero_spider_boy.id` => `hero_spider_boy.team_id`. PR [#106](https://github.com/tiangolo/sqlmodel/pull/106) by [@yoannmos](https://github.com/yoannmos).\n* 🎨 Remove unwanted highlight in the docs. PR [#233](https://github.com/tiangolo/sqlmodel/pull/233) by [@jalvaradosegura](https://github.com/jalvaradosegura).\n* ✏ Fix typos in `docs/databases.md` and `docs/tutorial/index.md`. PR [#35](https://github.com/tiangolo/sqlmodel/pull/35) by [@prrao87](https://github.com/prrao87).\n* ✏ Fix typo in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#239](https://github.com/tiangolo/sqlmodel/pull/239) by [@jalvaradosegura](https://github.com/jalvaradosegura).\n* ✏ Fix typo in `docs/tutorial/fastapi/simple-hero-api.md`. PR [#80](https://github.com/tiangolo/sqlmodel/pull/80) by [@joemudryk](https://github.com/joemudryk).\n* ✏ Fix typos in multiple files in the docs. PR [#400](https://github.com/tiangolo/sqlmodel/pull/400) by [@VictorGambarini](https://github.com/VictorGambarini).\n* ✏ Fix typo in `docs/tutorial/code-structure.md`. PR [#344](https://github.com/tiangolo/sqlmodel/pull/344) by [@marciomazza](https://github.com/marciomazza).\n* ✏ Fix typo in `docs/db-to-code.md`. PR [#155](https://github.com/tiangolo/sqlmodel/pull/155) by [@gr8jam](https://github.com/gr8jam).\n* ✏ Fix typo in `docs/contributing.md`. PR [#323](https://github.com/tiangolo/sqlmodel/pull/323) by [@Fardad13](https://github.com/Fardad13).\n* ✏ Fix typo in `docs/tutorial/fastapi/tests.md`. PR [#265](https://github.com/tiangolo/sqlmodel/pull/265) by [@johnhoman](https://github.com/johnhoman).\n* ✏ Fix typo in `docs/tutorial/where.md`. PR [#286](https://github.com/tiangolo/sqlmodel/pull/286) by [@jalvaradosegura](https://github.com/jalvaradosegura).\n* ✏ Fix typos in `docs/tutorial/fastapi/update.md`. PR [#268](https://github.com/tiangolo/sqlmodel/pull/268) by [@cirrusj](https://github.com/cirrusj).\n* ✏ Fix typo in `docs/tutorial/fastapi/simple-hero-api.md`. PR [#247](https://github.com/tiangolo/sqlmodel/pull/247) by [@hao-wang](https://github.com/hao-wang).\n* ✏ Fix typos in `docs/tutorial/automatic-id-none-refresh.md`, `docs/tutorial/fastapi/update.md`, `docs/tutorial/select.md`. PR [#185](https://github.com/tiangolo/sqlmodel/pull/185) by [@rootux](https://github.com/rootux).\n* ✏ Fix typo in `docs/databases.md`. PR [#177](https://github.com/tiangolo/sqlmodel/pull/177) by [@seandlg](https://github.com/seandlg).\n* ✏ Fix typos in `docs/tutorial/fastapi/update.md`. PR [#162](https://github.com/tiangolo/sqlmodel/pull/162) by [@wmcgee3](https://github.com/wmcgee3).\n* ✏ Fix typos in `docs/tutorial/code-structure.md`, `docs/tutorial/fastapi/multiple-models.md`, `docs/tutorial/fastapi/simple-hero-api.md`, `docs/tutorial/many-to-many/index.md`. PR [#116](https://github.com/tiangolo/sqlmodel/pull/116) by [@moonso](https://github.com/moonso).\n* ✏ Fix typo in `docs/tutorial/fastapi/teams.md`. PR [#154](https://github.com/tiangolo/sqlmodel/pull/154) by [@chrisgoddard](https://github.com/chrisgoddard).\n* ✏ Fix typo variable in example about relationships and `back_populates`, always use `hero` instead of `owner`. PR [#120](https://github.com/tiangolo/sqlmodel/pull/120) by [@onionj](https://github.com/onionj).\n* ✏ Fix typo in `docs/tutorial/fastapi/tests.md`. PR [#113](https://github.com/tiangolo/sqlmodel/pull/113) by [@feanil](https://github.com/feanil).\n* ✏ Fix typo in `docs/tutorial/where.md`. PR [#72](https://github.com/tiangolo/sqlmodel/pull/72) by [@ZettZet](https://github.com/ZettZet).\n* ✏ Fix typo in `docs/tutorial/code-structure.md`. PR [#91](https://github.com/tiangolo/sqlmodel/pull/91) by [@dhiraj](https://github.com/dhiraj).\n* ✏ Fix broken link to newsletter sign-up in `docs/help.md`. PR [#84](https://github.com/tiangolo/sqlmodel/pull/84) by [@mborus](https://github.com/mborus).\n* ✏ Fix typos in `docs/tutorial/many-to-many/create-models-with-link.md`. PR [#45](https://github.com/tiangolo/sqlmodel/pull/45) by [@xginn8](https://github.com/xginn8).\n* ✏ Fix typo in `docs/tutorial/index.md`. PR [#398](https://github.com/tiangolo/sqlmodel/pull/398) by [@ryangrose](https://github.com/ryangrose).\n\n### Internal\n\n* ♻ Refactor internal statements to simplify code. PR [#53](https://github.com/tiangolo/sqlmodel/pull/53) by [@yezz123](https://github.com/yezz123).\n* ♻ Refactor internal imports to reduce redundancy. PR [#272](https://github.com/tiangolo/sqlmodel/pull/272) by [@aminalaee](https://github.com/aminalaee).\n* ⬆ Update development requirement for FastAPI from `^0.68.0` to `^0.68.1`. PR [#48](https://github.com/tiangolo/sqlmodel/pull/48) by [@alucarddelta](https://github.com/alucarddelta).\n* ⏪ Revert upgrade Poetry, to make a release that supports Python 3.6 first. PR [#417](https://github.com/tiangolo/sqlmodel/pull/417) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add dependabot for GitHub Actions. PR [#410](https://github.com/tiangolo/sqlmodel/pull/410) by [@tiangolo](https://github.com/tiangolo).\n* ⬆️ Upgrade Poetry to version `==1.2.0b1`. PR [#303](https://github.com/tiangolo/sqlmodel/pull/303) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Add CI for Python 3.10. PR [#305](https://github.com/tiangolo/sqlmodel/pull/305) by [@tiangolo](https://github.com/tiangolo).\n* 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#263](https://github.com/tiangolo/sqlmodel/pull/263) by [@tiangolo](https://github.com/tiangolo).\n* 👷 Upgrade Codecov GitHub Action. PR [#304](https://github.com/tiangolo/sqlmodel/pull/304) by [@tiangolo](https://github.com/tiangolo).\n* 💚 Only run CI on push when on master, to avoid duplicate runs on PRs. PR [#244](https://github.com/tiangolo/sqlmodel/pull/244) by [@tiangolo](https://github.com/tiangolo).\n* 🔧 Upgrade MkDocs Material and update configs. PR [#217](https://github.com/tiangolo/sqlmodel/pull/217) by [@tiangolo](https://github.com/tiangolo).\n* ⬆ Upgrade mypy, fix type annotations. PR [#218](https://github.com/tiangolo/sqlmodel/pull/218) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.6\n\n### Breaking Changes\n\n**SQLModel** no longer creates indexes by default for every column, indexes are now opt-in. You can read more about it in PR [#205](https://github.com/tiangolo/sqlmodel/pull/205).\n\nBefore this change, if you had a model like this:\n\n```Python\nfrom typing import Optional\n\nfrom sqlmodel import Field, SQLModel\n\n\nclass Hero(SQLModel, table=True):\n    id: Optional[int] = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: Optional[int] = None\n```\n\n...when creating the tables, SQLModel version `0.0.5` and below, would also create an index for `name`, one for `secret_name`, and one for `age` (`id` is the primary key, so it doesn't need an additional index).\n\nIf you depended on having an index for each one of those columns, now you can (and would have to) define them explicitly:\n\n```Python\nclass Hero(SQLModel, table=True):\n    id: Optional[int] = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str = Field(index=True)\n    age: Optional[int] = Field(default=None, index=True)\n```\n\nThere's a high chance you don't need indexes for all the columns. For example, you might only need indexes for `name` and `age`, but not for `secret_name`. In that case, you could define the model as:\n\n```Python\nclass Hero(SQLModel, table=True):\n    id: Optional[int] = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: Optional[int] = Field(default=None, index=True)\n```\n\nIf you already created your database tables with SQLModel using versions `0.0.5` or below, it would have also created those indexes in the database. In that case, you might want to manually drop (remove) some of those indexes, if they are unnecessary, to avoid the extra cost in performance and space.\n\nDepending on the database you are using, there will be a different way to find the available indexes.\n\nFor example, let's say you no longer need the index for `secret_name`. You could check the current indexes in the database and find the one for `secret_name`, it could be named `ix_hero_secret_name`. Then you can remove it with SQL:\n\n```SQL\nDROP INDEX ix_hero_secret_name\n```\n\nor\n\n```SQL\nDROP INDEX ix_hero_secret_name ON hero;\n```\n\nHere's the new, extensive documentation explaining indexes and how to use them: [Indexes - Optimize Queries](https://sqlmodel.tiangolo.com/tutorial/indexes/).\n\n### Docs\n\n* ✨ Document indexes and make them opt-in. Here's the new documentation: [Indexes - Optimize Queries](https://sqlmodel.tiangolo.com/tutorial/indexes/). This is the same change described above in **Breaking Changes**. PR [#205](https://github.com/tiangolo/sqlmodel/pull/205) by [@tiangolo](https://github.com/tiangolo).\n* ✏ Fix typo in FastAPI tutorial. PR [#192](https://github.com/tiangolo/sqlmodel/pull/192) by [@yaquelinehoyos](https://github.com/yaquelinehoyos).\n* 📝 Add links to the license file. PR [#29](https://github.com/tiangolo/sqlmodel/pull/29) by [@sobolevn](https://github.com/sobolevn).\n* ✏ Fix typos in docs titles. PR [#28](https://github.com/tiangolo/sqlmodel/pull/28) by [@Batalex](https://github.com/Batalex).\n* ✏ Fix multiple typos and some rewording. PR [#22](https://github.com/tiangolo/sqlmodel/pull/22) by [@egrim](https://github.com/egrim).\n* ✏ Fix typo in `docs/tutorial/automatic-id-none-refresh.md`. PR [#14](https://github.com/tiangolo/sqlmodel/pull/14) by [@leynier](https://github.com/leynier).\n* ✏ Fix typos in `docs/tutorial/index.md` and `docs/databases.md`. PR [#5](https://github.com/tiangolo/sqlmodel/pull/5) by [@sebastianmarines](https://github.com/sebastianmarines).\n\n## 0.0.5\n\n### Features\n\n* ✨ Add support for Decimal fields from Pydantic and SQLAlchemy. Original PR [#103](https://github.com/tiangolo/sqlmodel/pull/103) by [@robcxyz](https://github.com/robcxyz). New docs: [Advanced User Guide - Decimal Numbers](https://sqlmodel.tiangolo.com/advanced/decimal/).\n\n### Docs\n\n* ✏ Update decimal tutorial source for consistency. PR [#188](https://github.com/tiangolo/sqlmodel/pull/188) by [@tiangolo](https://github.com/tiangolo).\n\n### Internal\n\n* 🔧 Split MkDocs insiders build in CI to support building from PRs. PR [#186](https://github.com/tiangolo/sqlmodel/pull/186) by [@tiangolo](https://github.com/tiangolo).\n* 🎨 Format `expression.py` and expression template, currently needed by CI. PR [#187](https://github.com/tiangolo/sqlmodel/pull/187) by [@tiangolo](https://github.com/tiangolo).\n* 🐛Fix docs light/dark theme switcher. PR [#1](https://github.com/tiangolo/sqlmodel/pull/1) by [@Lehoczky](https://github.com/Lehoczky).\n* 🔧 Add MkDocs Material social cards. PR [#90](https://github.com/tiangolo/sqlmodel/pull/90) by [@tiangolo](https://github.com/tiangolo).\n* ✨ Update type annotations and upgrade mypy. PR [#173](https://github.com/tiangolo/sqlmodel/pull/173) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.4\n\n* 🎨 Fix type detection of select results in PyCharm. PR [#15](https://github.com/tiangolo/sqlmodel/pull/15) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.3\n\n* ⬆️ Update and relax specification range for `sqlalchemy-stubs`. PR [#4](https://github.com/tiangolo/sqlmodel/pull/4) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.2\n\n* This includes several small bug fixes detected during the first CI runs.\n* 💚 Fix CI installs and tests. PR [#2](https://github.com/tiangolo/sqlmodel/pull/2) by [@tiangolo](https://github.com/tiangolo).\n\n## 0.0.1\n\n* First release. 🎉\n"
  },
  {
    "path": "docs/resources/index.md",
    "content": "# Resources\n\nAdditional resources, how to **help** and get help, how to **contribute**, and more. ✈️\n"
  },
  {
    "path": "docs/tutorial/automatic-id-none-refresh.md",
    "content": "# Automatic IDs, None Defaults, and Refreshing Data\n\nIn the previous chapter, we saw how to add rows to the database using **SQLModel**.\n\nNow let's talk a bit about why the `id` field **can't be `NULL`** on the database because it's a **primary key**, and we declare it using `Field(primary_key=True)`.\n\nBut the same `id` field actually **can be `None`** in the Python code, so we declare the type with `int | None`, and set the default value to `Field(default=None)`:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[4:8] hl[5] *}\n\nNext, I'll show you a bit more about the synchronization of data between the database and the Python code.\n\nWhen do we get an actual `int` from the database in that `id` field? Let's see all that. 👇\n\n## Create a New `Hero` Instance\n\nWhen we create a new `Hero` instance, we don't set the `id`:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[21:24] hl[21:24] *}\n\n### How `int | None` Helps\n\nBecause we don't set the `id`, it takes the Python's default value of `None` that we set in `Field(default=None)`.\n\nThis is the only reason why we define it with `int | None` and with a default value of `None`.\n\nBecause at this point in the code, **before interacting with the database**, the Python value could actually be `None`.\n\nIf we assumed that the `id` was *always* an `int` and added the type annotation without `int | None`, we could end up writing broken code, like:\n\n```Python\nnext_hero_id = hero_1.id + 1\n```\n\nIf we ran this code before saving the hero to the database and the `hero_1.id` was still `None`, we would get an error like:\n\n```\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'int'\n```\n\nBut by declaring it with `int | None`, the editor will help us to avoid writing broken code by showing us a warning telling us that the code could be invalid if `hero_1.id` is `None`. 🔍\n\n## Print the Default `id` Values\n\nWe can confirm that by printing our heroes before adding them to the database:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[21:29] hl[27:29] *}\n\nThat will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\nBefore interacting with the database\nHero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\nHero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\nHero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\n```\n\n</div>\n\nNotice they all have `id=None`.\n\nThat's the default value we defined in the `Hero` model class.\n\nWhat happens when we `add` these objects to the **session**?\n\n## Add the Objects to the Session\n\nAfter we add the `Hero` instance objects to the **session**, the IDs are *still* `None`.\n\nWe can verify by creating a session using a `with` block and adding the objects. And then printing them again:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[21:39] hl[37:39] *}\n\nThis will, again, output the `id`s of the objects as `None`:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\nAfter adding to the session\nHero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\nHero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\nHero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\n```\n\n</div>\n\nAs we saw before, the **session** is smart and doesn't talk to the database every time we prepare something to be changed, only after we are ready and tell it to `commit` the changes it goes and sends all the SQL to the database to store the data.\n\n## Commit the Changes to the Database\n\nThen we can `commit` the changes in the session, and print again:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[31:46] hl[41,44:46] *}\n\nAnd now, something unexpected happens, look at the output, it seems as if the `Hero` instance objects had no data at all:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\n// Here the engine talks to the database, the SQL part\nINFO Engine BEGIN (implicit)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00018s] ('Deadpond', 'Dive Wilson', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.0008968s ago] ('Spider-Boy', 'Pedro Parqueador', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001143s ago] ('Rusty-Man', 'Tommy Sharp', 48)\nINFO Engine COMMIT\n\n// And now our prints\nAfter committing the session\nHero 1:\nHero 2:\nHero 3:\n\n// What is happening here? 😱\n```\n\n</div>\n\nWhat happens is that SQLModel (actually SQLAlchemy) is internally marking those objects as \"expired\", they **don't have the latest version of their data**. This is because we could have some fields updated in the database, for example, imagine a field `updated_at: datetime` that was automatically updated when we saved changes.\n\nThe same way, other values could have changed, so the option the **session** has to be sure and safe is to just internally mark the objects as expired.\n\nAnd then, next time we access each attribute, for example with:\n\n```Python\ncurrent_hero_name = hero_1.name\n```\n\n...SQLModel (actually SQLAlchemy) will make sure to contact the database and **get the most recent version of the data**, updating that field `name` in our object and then making it available for the rest of the Python expression. In the example above, at that point, Python would be able to continue executing and use that `hero_1.name` value (just updated) to put it in the variable `current_hero_name`.\n\nAll this happens automatically and behind the scenes. ✨\n\nAnd here's the funny and strange thing with our example:\n\n```Python\nprint(\"Hero 1:\", hero_1)\n```\n\nWe didn't access the object's attributes, like `hero.name`. We only accessed the entire object and printed it, so **SQLAlchemy has no way of knowing** that we want to access this object's data.\n\n## Print a Single Field\n\nTo confirm and understand how this **automatic expiration and refresh** of data when accessing attributes work, we can print some individual fields (instance attributes):\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[31:56] hl[49:51,54:56] *}\n\nNow we are actually accessing the attributes, because instead of printing the whole object `hero_1`:\n\n```Python\nprint(\"Hero 1:\", hero_1)\n```\n\n...we are now printing the `id` attribute in `hero.id`:\n\n```Python\nprint(\"Hero 1 ID:\", hero_1.id)\n```\n\nBy accessing the attribute, that **triggers** a lot of work done by SQLModel (actually SQLAlchemy) underneath to **refresh the data from the database**, set it in the object's `id` attribute, and make it available for the Python expression (in this case just to print it).\n\nLet's see how it works:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\n// After committing, the objects are expired and have no values\nAfter committing the session\nHero 1:\nHero 2:\nHero 3:\n\n// Now we will access an attribute like the ID, this is the first print\nAfter committing the session, show IDs\n\n// Notice that before printing the first ID, the Session makes the Engine go to the database to refresh the data 🤓\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00017s] (1,)\n\n// Here's our first print, now we have the database-generated ID\nHero 1 ID: 1\n\n// Before the next print, refresh the data for the second object\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.001245s ago] (2,)\n\n// Here's our print for the second hero with its auto-generated ID\nHero 2 ID: 2\n\n// Before the third print, refresh its data\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.002215s ago] (3,)\n\n// And here's our print for the third hero\nHero 3 ID: 3\n\n// What if we print another attribute like the name?\nAfter committing the session, show names\nHero 1 name: Deadpond\nHero 2 name: Spider-Boy\nHero 3 name: Rusty-Man\n\n// Because the Session already refreshed these objects with all their data and the session knows they are not expired, it doesn't have to go again to the database for the names 🤓\n```\n\n</div>\n\n## Refresh Objects Explicitly\n\nYou just learnt how the **session** refreshes the data automatically behind the scenes, as a side effect, when you access an attribute.\n\nBut what if you want to **explicitly refresh** the data?\n\nYou can do that too with `session.refresh(object)`:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[31:65] hl[58:60,63:65] *}\n\nWhen Python executes this code:\n\n```Python\nsession.refresh(hero_1)\n```\n\n...the **session** goes and makes the **engine** communicate with the database to get the recent data for this object `hero_1`, and then the **session** puts the data in the `hero_1` object and marks it as \"fresh\" or \"not expired\".\n\nHere's how the output would look like:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\n// The first refresh\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00024s] (1,)\n\n// The second refresh\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.001487s ago] (2,)\n\n// The third refresh\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.002377s ago] (3,)\n\n// Now print the data, as it's already refreshed there's no need for the Session to go and refresh it again\nAfter refreshing the heroes\nHero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\nHero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\nHero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\n```\n\n</div>\n\nThis could be useful, for example, if you are building a web API to create heroes. And once a hero is created with some data, you return it to the client.\n\nYou wouldn't want to return an object that looks empty because the automatic magic to refresh the data was not triggered.\n\nIn this case, after committing the object to the database with the **session**, you could refresh it, and then return it to the client. This would ensure that the object has its fresh data.\n\n## Print Data After Closing the Session\n\nNow, as a final experiment, we can also print data after the **session** is closed.\n\nThere are no surprises here, it still works:\n\n{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[31:70] hl[68:70] *}\n\nAnd the output shows again the same data:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Output above omitted 👆\n\n// By finishing the with block, the Session is closed, including a rollback of any pending transaction that could have been there and was not committed\nINFO Engine ROLLBACK\n\n// Then we print the data, it works normally\nAfter the session closes\nHero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\nHero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\nHero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\n```\n\n</div>\n\n## Review All the Code\n\nNow let's review all this code once again.\n\n/// tip\n\nEach one of the numbered bubbles shows what each line will print in the output.\n\nAnd as we created the **engine** with `echo=True`, we can see the SQL statements being executed at each step.\n\n///\n\n//// tab | Python 3.10+\n\n```Python\n{!./docs_src/tutorial/automatic_id_none_refresh/tutorial002_py310.py!}\n```\n\n{!./docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md!}\n\n////\n\nAnd here's all the output generated by running this program, all together:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\nINFO Engine BEGIN (implicit)\nINFO Engine PRAGMA main.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine PRAGMA temp.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine\nCREATE TABLE hero (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        PRIMARY KEY (id)\n)\n\n\nINFO Engine [no key 0.00018s] ()\nINFO Engine COMMIT\nBefore interacting with the database\nHero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\nHero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\nHero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\nAfter adding to the session\nHero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\nHero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\nHero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\nINFO Engine BEGIN (implicit)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00022s] ('Deadpond', 'Dive Wilson', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001127s ago] ('Spider-Boy', 'Pedro Parqueador', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001483s ago] ('Rusty-Man', 'Tommy Sharp', 48)\nINFO Engine COMMIT\nAfter committing the session\nHero 1:\nHero 2:\nHero 3:\nAfter committing the session, show IDs\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00029s] (1,)\nHero 1 ID: 1\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.002132s ago] (2,)\nHero 2 ID: 2\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.003367s ago] (3,)\nHero 3 ID: 3\nAfter committing the session, show names\nHero 1 name: Deadpond\nHero 2 name: Spider-Boy\nHero 3 name: Rusty-Man\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00025s] (1,)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.001583s ago] (2,)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.002722s ago] (3,)\nAfter refreshing the heroes\nHero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\nHero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\nHero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\nINFO Engine ROLLBACK\nAfter the session closes\nHero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\nHero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\nHero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\n```\n\n</div>\n\n## Recap\n\nYou read all that! That was a lot! Have some cake, you earned it. 🍰\n\nWe discussed how the **session** uses the **engine** to send SQL to the database, to create data and to fetch data too. How it keeps track of \"**expired**\" and \"**fresh**\" data. At which moments it **fetches data automatically** (when accessing instance attributes) and how that data is synchronized between objects in memory and the database via the **session**.\n\nIf you understood all that, now you know a lot about **SQLModel**, SQLAlchemy, and how the interactions from Python with databases work in general.\n\nIf you didn't get all that, it's fine, you can always come back later to <abbr title=\"See what I did there? 😜\">`refresh`</abbr> the concepts.\n\nI think this might be one of the main types of bugs that cause problems and makes you scratch your head. So, good job studying it! 💪\n"
  },
  {
    "path": "docs/tutorial/code-structure.md",
    "content": "# Code Structure and Multiple Files\n\nLet's stop for a second to think about how to structure the code, particularly in **large projects** with multiple files.\n\n## Circular Imports\n\nThe class `Hero` has a reference to the class `Team` internally.\n\nBut the class `Team` also has a reference to the class `Hero`.\n\nSo, if those two classes were in separate files and you tried to import the classes in each other's file directly, it would result in a **circular import**. 🔄\n\nAnd Python will not be able to handle it and will throw an error. 🚨\n\nBut we actually want to *mean* that **circular reference**, because in our code, we would be able to do crazy things like:\n\n```Python\nhero.team.heroes[0].team.heroes[1].team.heroes[2].name\n```\n\nAnd that circular reference is what we are expressing with these **relationship attributes**, that:\n\n* A hero can have a team\n    * That team can have a list of heroes\n        * Each of those heroes can have a team\n            * ...and so on.\n\nLet's see different strategies to **structure the code** accounting for this.\n\n## Single Module for Models\n\nThis is the simplest way. ✨\n\nIn this solution we are still using **multiple files**, for the `models`, for the `database`, and for the `app`.\n\nAnd we could have any **other files** necessary.\n\nBut in this first case, all the models would live in a **single file**.\n\nThe file structure of the project could be:\n\n```\n.\n├── project\n    ├── __init__.py\n    ├── app.py\n    ├── database.py\n    └── models.py\n```\n\nWe have 3 <abbr title=\"Python files that can be imported or run\">**Python modules**</abbr> (or files):\n\n* `app`\n* `database`\n* `models`\n\nAnd we also have an empty `__init__.py` file to make this project a \"**Python package**\" (a collection of Python modules). This way we can use **relative imports** in the `app.py` file/module, like:\n\n```Python\nfrom .models import Hero, Team\nfrom .database import engine\n```\n\nWe can use these relative imports because, for example, in the file `app.py` (the `app` module) Python knows that it is **part of our Python package** because it is in the same directory as the file `__init__.py`. And all the Python files on the same directory are part of the same Python package too.\n\n### Models File\n\nYou could put all the database Models in a single Python module (a single Python file), for example `models.py`:\n\n{* ./docs_src/tutorial/code_structure/tutorial001_py310/models.py *}\n\nThis way, you wouldn't have to deal with circular imports for other models.\n\nAnd then you could import the models from this file/module in any other file/module in your application.\n\n### Database File\n\nThen you could put the code creating the **engine** and the function to create all the tables (if you are not using migrations) in another file `database.py`:\n\n{* ./docs_src/tutorial/code_structure/tutorial001_py310/database.py *}\n\nThis file would also be imported by your application code, to use the shared **engine** and to get and call the function `create_db_and_tables()`.\n\n### Application File\n\nFinally, you could put the code to create the **app** in another file `app.py`:\n\n{* ./docs_src/tutorial/code_structure/tutorial001_py310/app.py hl[3:4] *}\n\nHere we import the models, the engine, and the function to create all the tables and then we can use them all internally.\n\n### Order Matters\n\nRemember that [Order Matters](create-db-and-table.md#sqlmodel-metadata-order-matters){.internal-link target=_blank} when calling `SQLModel.metadata.create_all()`?\n\nThe point of that section in the docs is that you have to import the module that has the models **before** calling `SQLModel.metadata.create_all()`.\n\nWe are doing that here, we import the models in `app.py` and **after** that we create the database and tables, so we are fine and everything works correctly. 👌\n\n### Run It in the Command Line\n\nBecause now this is a larger project with a **Python package** and not a single Python file, we **cannot** call it just passing a single file name as we did before with:\n\n```console\n$ python app.py\n```\n\nNow we have to tell Python that we want it to execute a *module* that is part of a package:\n\n```console\n$ python -m project.app\n```\n\nThe `-m` is to tell Python to call a *module*. And the next thing we pass is a string with `project.app`, that is the same format we would use in an **import**:\n\n```Python\nimport project.app\n```\n\nThen Python will execute that module *inside* of that package, and because Python is executing it directly, the same trick with the **main block** that we have in `app.py` will still work:\n\n```Python\nif __name__ == '__main__':\n    main()\n```\n\nSo, the output would be:\n\n<div class=\"termy\">\n\n```console\n$ python -m project.app\n\nCreated hero: id=1 secret_name='Dive Wilson' team_id=1 name='Deadpond' age=None\nHero's team: name='Z-Force' headquarters='Sister Margaret's Bar' id=1\n```\n\n</div>\n\n## Make Circular Imports Work\n\nLet's say that for some reason you hate the idea of having all the database models together in a single file, and you really want to have **separate files**: a `hero_model.py` file and a `team_model.py` file.\n\nYou can also do it. 😎 There's a couple of things to keep in mind. 🤓\n\n/// warning\n\nThis is a bit more advanced.\n\nIf the solution above already worked for you, that might be enough for you, and you can continue in the next chapter. 🤓\n\n///\n\nLet's assume that now the file structure is:\n\n```\n.\n├── project\n    ├── __init__.py\n    ├── app.py\n    ├── database.py\n    ├── hero_model.py\n    └── team_model.py\n```\n\n### Circular Imports and Type Annotations\n\nThe problem with circular imports is that Python can't resolve them at <abbr title=\"While it is executing the program, as opposed to the code as just text in a file stored on disk.\">*runtime*</abbr>.\n\nBut when using Python **type annotations** it's very common to need to declare the type of some variables with classes imported from other files.\n\nAnd the files with those classes might **also need to import** more things from the first files.\n\nAnd this ends up *requiring* the same **circular imports** that are not supported in Python at *runtime*.\n\n### Type Annotations and Runtime\n\nBut these **type annotations** we want to declare are not needed at *runtime*.\n\nIn fact, remember that we used `list[\"Hero\"]`, with a `\"Hero\"` in a string?\n\nFor Python, at runtime, that is **just a string**.\n\nSo, if we could add the type annotations we need using the **string versions**, Python wouldn't have a problem.\n\nBut if we just put strings in the type annotations, without importing anything, the editor wouldn't know what we mean, and wouldn't be able to help us with **autocompletion** and **inline errors**.\n\nSo, if there was a way to \"import\" some things that act as \"imported\" only while editing the code but not at <abbr title=\"When Python is executing the code.\">*runtime*</abbr>, that would solve it... And it exists! Exactly that. 🎉\n\n### Import Only While Editing with `TYPE_CHECKING`\n\nTo solve it, there's a special trick with a special <abbr title=\"Technically it's a constant, it doesn't vary in the code 🤷\">variable</abbr> `TYPE_CHECKING` in the `typing` module.\n\nIt has a value of `True` for editors and tools that analyze the code with the type annotations.\n\nBut when Python is executing, its value is `False`.\n\nSo, we can use it in an `if` block and import things inside the `if` block. And they will be \"imported\" only for editors, but not at runtime.\n\n### Hero Model File\n\nUsing that trick of `TYPE_CHECKING` we can \"import\" the `Team` in `hero_model.py`:\n\n{* ./docs_src/tutorial/code_structure/tutorial002_py310/hero_model.py hl[1,5:6,16] *}\n\nHave in mind that now we *have* to put the annotation of `Team` as a string: `\"Team\"`, so that Python doesn't have errors at runtime.\n\n### Team Model File\n\nWe use the same trick in the `team_model.py` file:\n\n{* ./docs_src/tutorial/code_structure/tutorial002_py310/team_model.py hl[1,5:6,14] *}\n\nNow we get editor support, autocompletion, inline errors, and **SQLModel** keeps working. 🎉\n\n### App File\n\nNow, just for completeness, the `app.py` file would import the models from both modules:\n\n{* ./docs_src/tutorial/code_structure/tutorial002_py310/app.py hl[4:5,10,12:14] *}\n\nAnd of course, all the tricks with `TYPE_CHECKING` and type annotations in strings are **only needed in the files with circular imports**.\n\nAs there are no circular imports with `app.py`, we can just use normal imports and use the classes as normally here.\n\nAnd running that achieves the same result as before:\n\n<div class=\"termy\">\n\n```console\n$ python -m project.app\n\nCreated hero: id=1 age=None name='Deadpond' secret_name='Dive Wilson' team_id=1\nHero's team: id=1 name='Z-Force' headquarters='Sister Margaret's Bar'\n```\n\n</div>\n\n## Recap\n\nFor the **simplest cases** (for most of the cases) you can just keep all the models in a single file, and structure the rest of the application (including setting up the **engine**) in as many files as you want.\n\nAnd for the **complex cases** that really need separating all the models in different files, you can use the `TYPE_CHECKING` to make it all work and still have the best developer experience with the best editor support. ✨\n"
  },
  {
    "path": "docs/tutorial/connect/create-connected-rows.md",
    "content": "# Create and Connect Rows\n\nWe will now **create rows** for each table. ✨\n\nThe `team` table will look like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd after we finish working with the data in this chapter, the `hero` table will look like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>null</td>\n</tr>\n</table>\n\nEach row in the table `hero` will point to a row in the table `team`:\n\n<img alt=\"table relationships\" src=\"/img/tutorial/relationships/select/relationships2.drawio.svg\">\n\n/// info\n\nWe will later update **Spider-Boy** to add him to the **Preventers** team too, but not yet.\n\n///\n\nWe will continue with the code in the previous example and we will add more things to it.\n\n{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[0] *}\n\nMake sure you remove the `database.db` file before running the examples to get the same results.\n\n## Create Rows for Teams with **SQLModel**\n\nLet's do the same we did before and define a `create_heroes()` function where we create our heroes.\n\nAnd now we will also create the teams there. 🎉\n\nLet's start by creating two teams:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:35] hl[29:35] *}\n\nThis would hopefully look already familiar.\n\nWe start a **session** in a `with` block using the same **engine** we created above.\n\nThen we create two instances of the model class (in this case `Team`).\n\nNext we add those objects to the **session**.\n\nAnd finally we **commit** the session to save the changes to the database.\n\n## Add It to Main\n\nLet's not forget to add this function `create_heroes()` to the `main()` function so that we run it when calling the program from the command line:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[61:63] hl[63] *}\n\n## Run it\n\nIf we run that code we have up to now, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Automatically start a transaction\nINFO Engine BEGIN (implicit)\n// Add the teams to the database\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [generated in 0.00050s] ('Preventers', 'Sharp Tower')\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [cached since 0.002324s ago] ('Z-Force', 'Sister Margaret's Bar')\nINFO Engine COMMIT\n```\n\n</div>\n\nYou can see in the output that it uses common SQL `INSERT` statements to create the rows.\n\n## Create Rows for Heroes in Code\n\nNow let's create one hero object to start.\n\nAs the `Hero` class model now has a field (column, attribute) `team_id`, we can set it by using the ID field from the `Team` objects we just created before:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:39] hl[38] *}\n\nWe haven't committed this hero to the database yet, but there are already a couple of things to pay **attention** to.\n\nIf the database already had some teams, we wouldn't even know **what is the ID** that is going to be automatically assigned to each team by the database, for example, we couldn't just guess `1` or `2`.\n\nBut once the team is created and committed to the database, we can access the object's `id` field to get that ID.\n\nAccessing an attribute in a model that was just committed, for example with `team_z_force.id`, automatically **triggers a refresh** of the data from the DB in the object, and then exposes the value for that field.\n\nSo, even though we are not committing this hero yet, just because we are using `team_z_force.id`, that will trigger some SQL sent to the database to fetch the data for this team.\n\nThat line alone would generate an output of:\n\n```\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [generated in 0.00025s] (2,)\n```\n\nLet's now create two more heroes:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:50] hl[40:46] *}\n\nWhen creating `hero_rusty_man`, we are accessing `team_preventers.id`, so that will also trigger a refresh of its data, generating an output of:\n\n```\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [cached since 0.001795s ago] (1,)\n```\n\nThere's something else to note. We marked `team_id` as `int | None`, meaning that this could be `NULL` on the database (and `None` in Python).\n\nThat means that a hero doesn't have to have a team. And in this case, **Spider-Boy** doesn't have one.\n\nNext we just commit the changes to save them to the database, and that will generate the output:\n\n```\nINFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)\nINFO Engine [generated in 0.00022s] ('Deadpond', 'Dive Wilson', None, 2)\nINFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)\nINFO Engine [cached since 0.0007987s ago] ('Rusty-Man', 'Tommy Sharp', 48, 1)\nINFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)\nINFO Engine [cached since 0.001095s ago] ('Spider-Boy', 'Pedro Parqueador', None, None)\nINFO Engine COMMIT\n```\n\n## Refresh and Print Heroes\n\nNow let's refresh and print those new heroes to see their new ID pointing to their teams:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:58] hl[52:54,56:58] *}\n\nIf we execute that in the command line, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Automatically start a transaction\nINFO Engine BEGIN (implicit)\n\n// Refresh the first hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00021s] (1,)\n// Refresh the second hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.001575s ago] (2,)\n// Refresh the third hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.002518s ago] (3,)\n\n// Print the heroes\nCreated hero: id=1 secret_name='Dive Wilson' team_id=2 name='Deadpond' age=None\nCreated hero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48\nCreated hero: id=3 secret_name='Pedro Parqueador' team_id=None name='Spider-Boy' age=None\n```\n\n</div>\n\nThey now have their `team_id`s, nice!\n\n## Relationships\n\nRelationships in SQL databases are just made by having **columns in one table** referencing the values in **columns on other tables**.\n\nAnd here we have treated them just like that, more **column fields**, which is what they actually are behind the scenes in the SQL database.\n\nBut later in this tutorial, in the next group of chapters, you will learn about **Relationship Attributes** to make it all a lot easier to work with in code. ✨\n"
  },
  {
    "path": "docs/tutorial/connect/create-connected-tables.md",
    "content": "# Create Connected Tables\n\nNow we will deal with **connected** data put in different tables.\n\nSo, the first step is to create more than one table and connect them, so that each row in one table can reference another row in the other table.\n\nWe have been working with heroes in a single table `hero`. Let's now add a table `team`.\n\nThe team table will look like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nTo connect them, we will add another column to the hero table to point to each team by the ID with the `team_id`:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id ✨</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2 ✨</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1 ✨</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1 ✨</td>\n</tr>\n</table>\n\nThis way each row in the table `hero` can point to a row in the table `team`:\n\n<img alt=\"table relationships\" src=\"/img/databases/relationships.drawio.svg\">\n\n## One-to-Many and Many-to-One\n\nHere we are creating connected data in a relationship where **one** team could have **many** heroes. So it is commonly called a **one-to-many** or **many-to-one** relationship.\n\nThe **many-to-one** part can be seen if we start from the heroes, **many** heroes could be part of **one** team.\n\nThis is probably the most popular type of relationship, so we'll start with that. But there's also **many-to-many** and **one-to-one** relationships.\n\n## Create Tables in Code\n\n### Create the `team` Table\n\nLet's start by creating the tables in code.\n\nImport the things we need from `sqlmodel` and create a new `Team` model:\n\n{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[1:7] hl[4:7] *}\n\nThis is very similar to what we have been doing with the `Hero` model.\n\nThe `Team` model will be in a table automatically named `\"team\"`, and it will have the columns:\n\n* `id`, the primary key, automatically generated by the database\n* `name`, the name of the team\n    * We also tell **SQLModel** to create an index for this column\n* `headquarters`, the headquarters of the team\n\nAnd finally we mark it as a table in the config.\n\n### Create the New `hero` Table\n\nNow let's create the `hero` table.\n\nThis is the same model we have been using up to now, we are just adding the new column `team_id`:\n\n{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[1:16] hl[16] *}\n\nMost of that should look familiar:\n\nThe column will be named `team_id`. It will be an integer, and it could be `NULL` in the database (or `None` in Python), because there could be some heroes that don't belong to any team.\n\nWe add a default of `None` to the `Field()` so we don't have to explicitly pass `team_id=None` when creating a hero.\n\nNow, here's the new part:\n\nIn `Field()` we pass the argument `foreign_key=\"team.id\"`. This tells the database that this column `team_id` is a foreign key to the table `team`. A \"**foreign key**\" just means that this column will have the **key** to identify a row in a **foreign** table.\n\nThe value in this column `team_id` will be the same integer that is in some row in the `id` column on the `team` table. That is what connects the two tables.\n\n#### The Value of `foreign_key`\n\nNotice that the `foreign_key` is a string.\n\nInside it has the name of the **table**, then a dot, and then the name of the **column**.\n\nThis is the name of the **table** in the database, so it is `\"team\"`, not the name of the **model** class `Team` (with a capital `T`).\n\nIf you had a custom table name, you would use that custom table name.\n\n/// info\n\nYou can learn about setting a custom table name for a model in the Advanced User Guide.\n\n///\n\n### Create the Tables\n\nNow we can add the same code as before to create the engine and the function to create the tables:\n\n{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[19:26] hl[19:20,22,25:26] *}\n\nAnd as before, we'll call this function from another function `main()`, and we'll add that function `main()` to the main block of the file:\n\n{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[29:34] hl[29:30,33:34] *}\n\n## Run the Code\n\n/// tip\n\nBefore running the code, make sure you delete the file `database.db` to make sure you start from scratch.\n\n///\n\nIf we run the code we have up to now, it will go and create the database file `database.db` and the tables in it we just defined, `team` and `hero`:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Check if the tables exist already\nINFO Engine PRAGMA main.table_info(\"team\")\nINFO Engine [raw sql] ()\nINFO Engine PRAGMA temp.table_info(\"team\")\nINFO Engine [raw sql] ()\nINFO Engine PRAGMA main.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine PRAGMA temp.table_info(\"hero\")\nINFO Engine [raw sql] ()\n\n// Create the tables\nINFO Engine\nCREATE TABLE team (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        headquarters VARCHAR NOT NULL,\n        PRIMARY KEY (id)\n)\n\n\nINFO Engine [no key 0.00010s] ()\nINFO Engine\nCREATE TABLE hero (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id)\n)\n\n\nINFO Engine [no key 0.00026s] ()\nINFO Engine COMMIT\n```\n\n</div>\n\n## Create Tables in SQL\n\nLet's see that same generated SQL code.\n\nAs we saw before, those `VARCHAR` columns are converted to `TEXT` in SQLite, which is the database we are using for these experiments.\n\nSo, the first SQL could also be written as:\n\n```SQL\nCREATE TABLE team (\n    id INTEGER,\n    name TEXT NOT NULL,\n    headquarters TEXT NOT NULL,\n    PRIMARY KEY (id)\n)\n```\n\nAnd the second table could be written as:\n\n```SQL hl_lines=\"8\"\nCREATE TABLE hero (\n    id INTEGER,\n    name TEXT NOT NULL,\n    secret_name TEXT NOT NULL,\n    age INTEGER,\n    team_id INTEGER,\n    PRIMARY KEY (id),\n    FOREIGN KEY(team_id) REFERENCES team (id)\n)\n```\n\nThe only new  is the `FOREIGN KEY` line, and as you can see, it tells the database what column in this table is a foreign key (`team_id`), which other (foreign) table it references (`team`) and which column in that table is the key to define which row to connect (`id`).\n\nFeel free to experiment with it in **DB Browser for SQLite**.\n\n## Recap\n\nUsing **SQLModel**, in most of the cases you only need a field (column) with a `foreign_key` in the `Field()` with a string pointing to another table and column to connect two tables.\n\nNow that we have the tables created and connected, let's create some rows in the next chapter. 🚀\n"
  },
  {
    "path": "docs/tutorial/connect/index.md",
    "content": "# Connect Tables - JOIN - Intro\n\nBy this point, you already know how to perform the main <abbr title=\"Create, read, update, delete.\">CRUD</abbr> operations with **SQLModel** using a single table. 🎉\n\nBut the main advantage and feature of SQL databases is being able to handle related data, to **connect** or **\"join\"** different tables together. Connecting rows in one table to rows in another.\n\nLet's see how to use **SQLModel** to manage connected data in the next chapters. 🤝\n\n/// tip\n\nWe will extend this further in the next group of chapters making it even more convenient to work with in Python code, using **relationship attributes**.\n\nBut you should start in this group of chapters first. 🤓\n\n///\n"
  },
  {
    "path": "docs/tutorial/connect/read-connected-data.md",
    "content": "# Read Connected Data\n\nNow that we have some data in both tables, let's select the data that is connected together.\n\nThe `team` table has this data:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd the `hero` table has this data:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>null</td>\n</tr>\n</table>\n\nWe will continue with the code in the previous example and we will add more things to it.\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[0] *}\n\n## `SELECT` Connected Data with SQL\n\nLet's start seeing how SQL works when selecting connected data. This is where SQL databases actually shine.\n\nIf you don't have a `database.db` file, run that previous program we had written (or copy it from the preview above) to create it.\n\nNow open **DB Browser for SQLite** and open the `database.db` file.\n\nTo `SELECT` connected data we use the same keywords we have used before, but now we combine the two tables.\n\nLet's get each hero with the `id`, `name`, and the team `name`:\n\n```SQL\nSELECT hero.id, hero.name, team.name\nFROM hero, team\nWHERE hero.team_id = team.id\n```\n\n/// info\n\nBecause we have two columns called `name`, one for `hero` and one for `team`, we can specify them with the prefix of the table name and the dot to make it explicit what we refer to.\n\n///\n\nNotice that now in the `WHERE` part we are not comparing one column with a literal value (like `hero.name = \"Deadpond\"`), but we are comparing two columns.\n\nIt means, more or less:\n\n> Hey SQL database 👋, please go and `SELECT` some data for me.\n>\n> I'll first tell you the columns I want:\n>\n> * `id` of the `hero` table\n> * `name` of the `hero` table\n> * `name` of the `team` table\n>\n> I want you to get that data `FROM` the tables `hero` and `team`.\n>\n> And I don't want you to combine each hero with each possible team. Instead, for each hero, go and check each possible team, but give me only the ones `WHERE` the `hero.team_id` is the same as the `team.id`.\n\nIf we execute that SQL, it will return the table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Z-Force</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Preventers</td>\n</tr>\n</table>\n\nYou can go ahead and try it in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/relationships/select/image01.png\">\n\n/// note\n\nWait, what about Spider-Boy? 😱\n\nHe doesn't have a team, so his `team_id` is `NULL` in the database. And this SQL is comparing that `NULL` from the `team_id` with all the `id` fields in the rows in the `team` table.\n\nAs there's no team with an ID of `NULL`, it doesn't find a match.\n\nBut we'll see how to fix that later with a `LEFT JOIN`.\n\n///\n\n## Select Related Data with **SQLModel**\n\nNow let's use SQLModel to do the same select.\n\nWe'll create a function `select_heroes()` just as we did before, but now we'll work with two tables.\n\nRemember SQLModel's `select()` function? It can take more than one argument.\n\nSo, we can pass the `Hero` and `Team` model classes. And we can also use both their columns in the `.where()` part:\n\n{* ./docs_src/tutorial/connect/select/tutorial001_py310.py ln[61:63] hl[63] *}\n\nNotice that in the comparison with `==` we are using the class attributes for both `Hero.team_id` and `Team.id`.\n\nThat will generate the appropriate **expression** object that will be converted to the right SQL, equivalent to the SQL example we saw above.\n\nNow we can execute it and get the `results` object.\n\nAnd as we used `select` with two models, we will receive tuples of instances of those two models, so we can iterate over them naturally in a `for` loop:\n\n{* ./docs_src/tutorial/connect/select/tutorial001_py310.py ln[61:66] hl[65] *}\n\nFor each iteration in the `for` loop we get a tuple with an instance of the class `Hero` and an instance of the class `Team`.\n\nAnd in this `for` loop we assign them to the variable `hero` and the variable `team`.\n\n/// info\n\nThere was a lot of research, design, and work behind **SQLModel** to make this provide the best possible developer experience.\n\nAnd you should get autocompletion and inline errors in your editor for both `hero` and `team`. 🎉\n\n///\n\n## Add It to Main\n\nAs always, we must remember to add this new `select_heroes()` function to the `main()` function to make sure it is executed when we call this program from the command line.\n\n{* ./docs_src/tutorial/connect/select/tutorial001_py310.py ln[69:72] hl[72] *}\n\n## Run the Program\n\nNow we can run the program and see how it shows us each hero with their corresponding team:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Get the heroes with their teams\n2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters\nFROM hero, team\nWHERE hero.team_id = team.id\n2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine [no key 0.00015s] ()\n\n// Print the first hero and team\nHero: id=1 secret_name='Dive Wilson' team_id=2 name='Deadpond' age=None Team: headquarters='Sister Margaret's Bar' id=2 name='Z-Force'\n\n// Print the second hero and team\nHero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48 Team: headquarters='Sharp Tower' id=1 name='Preventers'\n2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine ROLLBACK\n```\n\n</div>\n\n## `JOIN` Tables with SQL\n\nThere's an alternative syntax for that SQL query from above using the keyword `JOIN` instead of `WHERE`.\n\nThis is the same version from above, using `WHERE`:\n\n```SQL\nSELECT hero.id, hero.name, team.name\nFROM hero, team\nWHERE hero.team_id = team.id\n```\n\nAnd this is the alternative version using `JOIN`:\n\n```SQL\nSELECT hero.id, hero.name, team.name\nFROM hero\nJOIN team\nON hero.team_id = team.id\n```\n\nBoth are equivalent. The differences in the SQL code are that instead of passing the `team` to the `FROM` part (also called `FROM` clause) we add a `JOIN` and put the `team` table there.\n\nAnd then, instead of putting a `WHERE` with a condition, we put an `ON` keyword with the condition, because `ON` is the one that comes with `JOIN`. 🤷\n\nSo, this second version means, more or less:\n\n> Hey SQL database 👋, please go and `SELECT` some data for me.\n>\n> I'll first tell you the columns I want:\n>\n> * `id` of the `hero` table\n> * `name` of the `hero` table\n> * `name` of the `team` table\n>\n> ...up to here it's the same as before, LOL.\n>\n> Now, I want you to get that data starting `FROM` the table `hero`.\n>\n> And to get the rest of the data, I want you to `JOIN` it with the table `team`.\n>\n> And I want you to join those two tables `ON` the combinations of rows that have the `hero.team_id` with the same value as the `team.id`.\n>\n> Did I say all this before already? I feel like I'm just repeating myself. 🤔\n\nThat will return the same table as before:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Z-Force</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Preventers</td>\n</tr>\n</table>\n\nAlso in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/relationships/select/image02.png\">\n\n/// tip\n\nWhy bother with all this if the result is the same?\n\nThis `JOIN` will be useful in a bit to be able to also get Spider-Boy, even if he doesn't have a team.\n\n///\n\n## Join Tables in **SQLModel**\n\nThe same way there's a `.where()` available when using `select()`, there's also a `.join()`.\n\nAnd in SQLModel (actually SQLAlchemy), when using the `.join()`, because we already declared what is the `foreign_key` when creating the models, we don't have to pass an `ON` part, it is inferred automatically:\n\n{* ./docs_src/tutorial/connect/select/tutorial002_py310.py ln[61:66] hl[63] *}\n\nAlso notice that we are still including `Team` in the `select(Hero, Team)`, because we still want to access that data.\n\nThis is equivalent to the previous example.\n\nAnd if we run it in the command line, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Select using a JOIN with automatic ON\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters\nFROM hero JOIN team ON team.id = hero.team_id\nINFO Engine [no key 0.00032s] ()\n\n// Print the first hero and team\nHero: id=1 secret_name='Dive Wilson' team_id=2 name='Deadpond' age=None Team: headquarters='Sister Margaret's Bar' id=2 name='Z-Force'\n\n// Print the second hero and team\nHero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48 Team: headquarters='Sharp Tower' id=1 name='Preventers'\n\n```\n\n</div>\n\n## `JOIN` Tables with SQL and `LEFT OUTER` (Maybe `JOIN`)\n\nWhen working with a `JOIN`, you can imagine that you start with a table on the `FROM` part and put that table in an imaginary space on the **left** side.\n\nAnd then you want another table to `JOIN` the result.\n\nAnd you put that second table in the **right** side on that imaginary space.\n\nAnd then you tell the database `ON` which condition it should join those two tables and give you the results back.\n\nBut by default, only the rows from both left and right that match the condition will be returned.\n\n<img alt=\"table relationships\" src=\"/img/databases/relationships.drawio.svg\">\n\nIn this example of tables above 👆, it would return all the heroes, because every hero has a `team_id`, so every hero can be joined with the `team` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Z-Force</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Preventers</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Preventers</td>\n</tr>\n</table>\n\n### Foreign Keys with `NULL`\n\nBut in the database that we are working with in the code above, **Spider-Boy** doesn't have any team, the value of `team_id` is `NULL` in the database.\n\nSo there's no way to join the **Spider-Boy** row with some row in the `team` table:\n\n<img alt=\"table relationships\" src=\"/img/tutorial/relationships/select/relationships2.drawio.svg\">\n\nRunning the same SQL we used above, the resulting table would not include **Spider-Boy** 😱:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Z-Force</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Preventers</td>\n</tr>\n</table>\n\n### Include Everything on the `LEFT OUTER`\n\nIn this case, that we want to include all heroes in the result even if they don't have a team, we can extend that same SQL using a `JOIN` from above and add a `LEFT OUTER` right before `JOIN`:\n\n```SQL hl_lines=\"3\"\nSELECT hero.id, hero.name, team.name\nFROM hero\nLEFT OUTER JOIN team\nON hero.team_id = team.id\n```\n\nThis `LEFT OUTER` part tells the database that we want to keep everything on the first table, the one on the `LEFT` in the imaginary space, even if those rows would be left **out**, so we want it to include the `OUTER` rows too. In this case, every hero with or without a team.\n\nAnd that would return the following result, including **Spider-Boy** 🎉:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Z-Force</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Preventers</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>null</td>\n</tr>\n</table>\n\n/// tip\n\nThe only difference between this query and the previous is that extra `LEFT OUTER`.\n\n///\n\nAnd here's another of the SQL variations, you could write `LEFT OUTER JOIN` or just `LEFT JOIN`, it means the same.\n\n## Join Tables in **SQLModel** with `LEFT OUTER`\n\nNow let's replicate the same query in **SQLModel**.\n\n`.join()` has a parameter we can use `isouter=True` to make the `JOIN` be a `LEFT OUTER JOIN`:\n\n{* ./docs_src/tutorial/connect/select/tutorial003_py310.py ln[61:66] hl[63] *}\n\nAnd if we run it, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// SELECT using LEFT OUTER JOIN\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters\nFROM hero LEFT OUTER JOIN team ON team.id = hero.team_id\n\nINFO Engine [no key 0.00051s] ()\n\n// Print the first hero and team\nHero: id=1 secret_name='Dive Wilson' team_id=2 name='Deadpond' age=None Team: headquarters='Sister Margaret's Bar' id=2 name='Z-Force'\n// Print the second hero and team\nHero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48 Team: headquarters='Sharp Tower' id=1 name='Preventers'\n// Print the third hero and team, we included Spider-Boy 🎉\nHero: id=3 secret_name='Pedro Parqueador' team_id=None name='Spider-Boy' age=None Team: None\n```\n\n</div>\n\n## What Goes in `select()`\n\nYou might be wondering why we put the `Team` in the `select()` and not just in the `.join()`.\n\nAnd then why we didn't include `Hero` in the `.join()`. 🤔\n\nIn SQLModel (actually in SQLAlchemy), all these functions and tools try to **replicate** how it would be to work with the **SQL** language.\n\nRemember that [`SELECT` defines the columns to get and `WHERE` how to filter them?](../where.md#select-and-where){.internal-link target=_blank}.\n\nThis also applies here, but with `JOIN` and `ON`.\n\n### Select Only Heroes But Join with Teams\n\nIf we only put the `Team` in the `.join()` and not in the `select()` function, we would not get the `team` data.\n\nBut we would still be able to **filter** the rows with it. 🤓\n\nWe could even add some additional `.where()` after `.join()` to filter the data more, for example to return only the heroes from one team:\n\n{* ./docs_src/tutorial/connect/select/tutorial004_py310.py ln[61:66] hl[63] *}\n\nHere we are **filtering** with `.where()` to get only the heroes that belong to the **Preventers** team.\n\nBut we are still only requesting the data from the heroes, not their teams.\n\nIf we run that, it would output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Select only the hero data\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\n// But still join with the team table\nFROM hero JOIN team ON team.id = hero.team_id\n// And filter with WHERE to get only the Preventers\nWHERE team.name = ?\nINFO Engine [no key 0.00066s] ('Preventers',)\n\n// We filter with the team, but only get the hero\nPreventer Hero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48\n```\n\n</div>\n\n### Include the `Team`\n\nBy putting the `Team` in `select()` we tell **SQLModel** and the database that we want the team data too.\n\n{* ./docs_src/tutorial/connect/select/tutorial005_py310.py ln[61:66] hl[63] *}\n\nAnd if we run that, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Select the hero and the team data\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters\n// Join the hero with the team table\nFROM hero JOIN team ON team.id = hero.team_id\n// Filter with WHERE to get only Preventers\nWHERE team.name = ?\nINFO Engine [no key 0.00018s] ('Preventers',)\n\n// Print the hero and the team\nPreventer Hero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48 Team: headquarters='Sharp Tower' id=1 name='Preventers'\n```\n\n</div>\n\nWe still have to `.join()` because otherwise it would just compute all the possible combinations of heroes and teams, for example including **Rusty-Man** with **Preventers** and also **Rusty-Man** with **Z-Force**, which would be a mistake.\n\n## Relationship Attributes\n\nHere we have been using the pure class models directly, but in a future chapter we will also see how to use **Relationship Attributes** that let us interact with the database in a way much more close to the code with Python objects.\n\nAnd we will also see how to load their data in a different, simpler way, achieving the same we achieved here. ✨\n"
  },
  {
    "path": "docs/tutorial/connect/remove-data-connections.md",
    "content": "# Remove Data Connections\n\nWe currently have a `team` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd a `hero` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n</table>\n\nLet's see how to **remove** connections between rows in tables.\n\nWe will continue with the code from the previous chapter.\n\n{* ./docs_src/tutorial/connect/update/tutorial001_py310.py ln[0] *}\n\n## Break a Connection\n\nWe don't really have to delete anything to break a connection. We can just assign `None` to the foreign key, in this case, to the `team_id`.\n\nLet's say **Spider-Boy** is tired of the lack of friendly neighbors and wants to get out of the **Preventers**.\n\nWe can simply set the `team_id` to `None`, and now it doesn't have a connection with the team:\n\n{* ./docs_src/tutorial/connect/delete/tutorial001_py310.py ln[29:30,66:70] hl[66] *}\n\nAgain, we just **assign** a value to that field attribute `team_id`, now the value is `None`, which means `NULL` in the database. Then we `add()` the hero to the session, and then `commit()`.\n\nNext we `refresh()` it to get the recent data, and we print it.\n\nRunning that in the command line will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Update the hero\nINFO Engine UPDATE hero SET team_id=? WHERE hero.id = ?\nINFO Engine [cached since 0.07753s ago] (None, 3)\n// Commit the session\nINFO Engine COMMIT\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n// Refresh the hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.1661s ago] (3,)\n\n// Print the hero without a team\nNo longer Preventer: id=3 secret_name='Pedro Parqueador' team_id=None name='Spider-Boy' age=None\n```\n\n</div>\n\nThat's it, we now removed a connection between rows in different tables by unsetting the foreign key column. 💥\n"
  },
  {
    "path": "docs/tutorial/connect/update-data-connections.md",
    "content": "# Update Data Connections\n\nAt this point we have a `team` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd a `hero` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>null</td>\n</tr>\n</table>\n\nSome of these heroes are part of a team.\n\nNow we'll see how to **update** those connections between rows tables.\n\nWe will continue with the code we used to create some heroes, and we'll update them.\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[0] *}\n\n## Assign a Team to a Hero\n\nLet's say that **Tommy Sharp** uses his \"rich uncle\" charms to recruit **Spider-Boy** to join the team of the **Preventers**, now we need to update our Spider-Boy hero object to connect it to the Preventers team.\n\nDoing it is just like updating any other field:\n\n{* ./docs_src/tutorial/connect/update/tutorial001_py310.py ln[29:30,60:64] hl[60] *}\n\nWe can simply **assign** a value to that field attribute `team_id`, then `add()` the hero to the session, and then `commit()`.\n\nNext we `refresh()` it to get the recent data, and we print it.\n\nRunning that in the command line will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 😉\n\n// Update the hero\nINFO Engine UPDATE hero SET team_id=? WHERE hero.id = ?\nINFO Engine [generated in 0.00014s] (1, 3)\n// Commit the session saving the changes\nINFO Engine COMMIT\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n// Refresh the hero data\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.08837s ago] (3,)\n\n// Print the updated hero\nUpdated hero: id=3 secret_name='Pedro Parqueador' team_id=1 name='Spider-Boy' age=None\n```\n\n</div>\n\nAnd now **Spider-Boy** has the `team_id=1`, which is the ID of the Preventers. 🎉\n\nLet's now see how to remove connections in the next chapter. 💥\n"
  },
  {
    "path": "docs/tutorial/create-db-and-table-with-db-browser.md",
    "content": "# Create a Table with SQL\n\nLet's get started!\n\nWe will:\n\n* Create a SQLite database with **DB Browser for SQLite**\n* Create a table in the database with **DB Browser for SQLite**\n\nWe'll add data later. For now, we'll create the database and the first table structure.\n\nWe will create a table to hold this data:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n## Create a Database\n\n**SQLModel** and SQLAlchemy are based on SQL.\n\nThey are designed to help you with using SQL through Python classes and objects. But it's still always very useful to understand SQL.\n\nSo let's start with a simple, pure SQL example.\n\nOpen **DB Browser for SQLite**.\n\nClick the button <kbd>New Database</kbd>.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image001.png\">\n\nA dialog should show up. Go to the [project directory you created](../virtual-environments.md#create-a-project){.internal-link target=_blank} and save the file with a name of `database.db`.\n\n/// tip\n\nIt's common to save SQLite database files with an extension of `.db`. Sometimes also `.sqlite`.\n\n///\n\n## Create a Table\n\nAfter doing that, it might prompt you to create a new table right away.\n\nIf it doesn't, click the button <kbd>Create Table</kbd>.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image002.png\">\n\nThen you will see the dialog to create a new table.\n\nSo, let's create a new table called `hero` with the following columns:\n\n* `id`: an `INTEGER` that will be the **primary key** (check `PK` ✅).\n* `name`: a `TEXT`, it should be `NOT NULL` (check `NN` ✅), so, it should always have a value.\n* `secret_name`: a `TEXT`, it should be `NOT NULL` too (check `NN` ✅).\n* `age`: an `INTEGER`, this one can be `NULL`, so you don't have to check anything else.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image003.png\">\n\nClick <kbd>OK</kbd> to create the table.\n\nWhile you click on the <kbd>Add</kbd> button and add the information, it will create and update the SQL statement that is executed to create the table:\n\n```{ .sql .annotate }\nCREATE TABLE \"hero\" ( --(1)\n  \"id\"  INTEGER, --(2)\n  \"name\"  TEXT NOT NULL, --(3)\n  \"secret_name\" TEXT NOT NULL, --(4)\n  \"age\" INTEGER, --(5)\n  PRIMARY KEY(\"id\") --(6)\n); --(7)\n```\n\n1. Create a table with the name `hero`. Also notice that the columns for this table are declared inside the parenthesis \" `(`\" that starts here.\n2. The `id` column, an `INTEGER`. This is declared as the primary key at the end.\n3. The `name` column, a `TEXT`, and it should always have a value `NOT NULL`.\n4. The `secret_name` column, another `TEXT`, also `NOT NULL`.\n5. The `age` column, an `INTEGER`. This one doesn't have `NOT NULL`, so it *can* be `NULL`.\n6. The `PRIMARY KEY` of all this is the `id` column.\n7. This is the end of the SQL table, with the final parenthesis \"`)`\". It also has the semicolon \"`;`\" that marks the end of the SQL statement. There could be more SQL statements in the same SQL string.\n\nNow you will see that it shows up in the list of Tables with the columns we specified. 🎉\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image004.png\">\n\nThe only step left is to click <kbd>Write Changes</kbd> to save the changes to the file.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image005.png\">\n\nAfter that, the new table is saved in this database on the file `./database.db`.\n\n## Confirm the Table\n\nLet's confirm that it's all saved.\n\nFirst click the button <kbd>Close Database</kbd> to close the database.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image006.png\">\n\nNow click on <kbd>Open Database</kbd> to open the database again, and select the same file `./database.db`.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image007.png\">\n\nYou will see again the same table we created.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image008.png\">\n\n## Create the Table again, with SQL\n\nNow, to see how is it that SQL works, let's create the table again, but with SQL.\n\nClick the <kbd>Close Database</kbd> button again.\n\nAnd delete that `./database.db` file in your project directory.\n\nAnd click again on <kbd>New Database</kbd>.\n\nSave the file with the name `database.db` again.\n\nThis time, if you see the dialog to create a new table, just close it by clicking the <kbd>Cancel</kbd> button.\n\nAnd now, go to the tab <kbd>Execute SQL</kbd>.\n\nWrite the same SQL that was generated in the previous step:\n\n```SQL\nCREATE TABLE \"hero\" (\n  \"id\"  INTEGER,\n  \"name\"  TEXT NOT NULL,\n  \"secret_name\" TEXT NOT NULL,\n  \"age\" INTEGER,\n  PRIMARY KEY(\"id\")\n);\n```\n\nThen click the \"Execute all\" <kbd>▶</kbd> button.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image009.png\">\n\nYou will see the \"execution finished successfully\" message.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image010.png\">\n\nAnd if you go back to the <kbd>Database Structure</kbd> tab, you will see that you effectively created again the same table.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image008.png\">\n\n## Learn More SQL\n\nI will keep showing you small bits of SQL through this tutorial. And you don't have to be a SQL expert to use **SQLModel**.\n\nBut if you are curious and want to get a quick overview of SQL, I recommend the visual documentation from SQLite, on <a href=\"https://www.sqlite.org/lang.html\" class=\"external-link\" target=\"_blank\">SQL As Understood By SQLite</a>.\n\nYou can start with <a href=\"https://www.sqlite.org/lang_createtable.html\" class=\"external-link\" target=\"_blank\">`CREATE TABLE`</a>.\n\nOf course, you can also go and take a full SQL course or read a book about SQL, but you don't need more than what I'll explain here on the tutorial to start being productive with **SQLModel**. 🤓\n\n## Recap\n\nWe saw how to interact with SQLite databases in files using **DB Browser for SQLite** in a visual user interface.\n\nWe also saw how to use it to write some SQL directly to the SQLite database. This will be useful to verify the data in the database is looking correctly, to debug, etc.\n\nIn the next chapters we will start using **SQLModel** to interact with the database, and we will continue to use **DB Browser for SQLite** at the same time to look at the database underneath. 🔍\n"
  },
  {
    "path": "docs/tutorial/create-db-and-table.md",
    "content": "# Create a Table with SQLModel - Use the Engine\n\nNow let's get to the code. 👩‍💻\n\nMake sure you are inside of your project directory and with your virtual environment activated as explained in [Virtual Environments](../virtual-environments.md#create-a-project){.internal-link target=_blank}.\n\nWe will:\n\n* Define a table with **SQLModel**\n* Create the same SQLite database and table with **SQLModel**\n* Use **DB Browser for SQLite** to confirm the operations\n\nHere's a reminder of the table structure we want:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n## Create the Table Model Class\n\nThe first thing we need to do is create a class to represent the data in the table.\n\nA class like this that represents some data is commonly called a **model**.\n\n/// tip\n\nThat's why this package is called `SQLModel`. Because it's mainly used to create **SQL Models**.\n\n///\n\nFor that, we will import `SQLModel` (plus other things we will also use) and create a class `Hero` that inherits from `SQLModel` and represents the **table model** for our heroes:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:8] hl[1,4] *}\n\nThis class `Hero` **represents the table** for our heroes. And each instance we create later will **represent a row** in the table.\n\nWe use the config `table=True` to tell **SQLModel** that this is a **table model**, it represents a table.\n\n/// info\n\nIt's also possible to have models without `table=True`, those would be only **data models**, without a table in the database, they would not be **table models**.\n\nThose **data models** will be **very useful later**, but for now, we'll just keep adding the `table=True` configuration.\n\n///\n\n## Define the Fields, Columns\n\nThe next step is to define the fields or columns of the class by using standard Python type annotations.\n\nThe name of each of these variables will be the name of the column in the table.\n\nAnd the type of each of them will also be the type of table column:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:8] hl[1,5:8] *}\n\nLet's now see with more detail these field/column declarations.\n\n### `None` Fields, Nullable Columns\n\nLet's start with `age`, notice that it has a type of `int | None`.\n\nThat is the standard way to declare that something \"could be an `int` or `None`\" in Python.\n\nAnd we also set the default value of `age` to `None`.\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:8] hl[8] *}\n\n/// tip\n\nWe also define `id` with `int | None`. But we will talk about `id` below.\n\n///\n\nBecause the type is `int | None`:\n\n* When validating data, `None` will be an allowed value for `age`.\n* In the database, the column for `age` will be allowed to have `NULL` (the SQL equivalent to Python's `None`).\n\nAnd because there's a default value `= None`:\n\n* When validating data, this `age` field won't be required, it will be `None` by default.\n* When saving to the database, the `age` column will have a `NULL` value by default.\n\n/// tip\n\nThe default value could have been something else, like `= 42`.\n\n///\n\n### Primary Key `id`\n\nNow let's review the `id` field. This is the <abbr title=\"That unique identifier of each row in a specific table.\">**primary key**</abbr> of the table.\n\nSo, we need to mark `id` as the **primary key**.\n\nTo do that, we use the special `Field` function from `sqlmodel` and set the argument `primary_key=True`:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:8] hl[1,5] *}\n\nThat way, we tell **SQLModel** that this `id` field/column is the primary key of the table.\n\nBut inside the SQL database, it is **always required** and can't be `NULL`. Why should we declare it with `int | None`?\n\nThe `id` will be required in the database, but it will be *generated by the database*, not by our code.\n\nSo, whenever we create an instance of this class (in the next chapters), we *will not set the `id`*. And the value of `id` will be `None` **until we save it in the database**, and then it will finally have a value.\n\n```Python\nmy_hero = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n\ndo_something(my_hero.id)  # Oh no! my_hero.id is None! 😱🚨\n\n# Imagine this saves it to the database\nsomehow_save_in_db(my_hero)\n\ndo_something(my_hero.id)  # Now my_hero.id has a value generated in DB 🎉\n```\n\nSo, because in *our code* (not in the database) the value of `id` *could be* `None`, we use `int | None`. This way **the editor will be able to help us**, for example, if we try to access the `id` of an object that we haven't saved in the database yet and would still be `None`.\n\n<img class=\"shadow\" src=\"/img/create-db-and-table/inline-errors01.png\">\n\nNow, because we are taking the place of the default value with our `Field()` function, we set **the actual default value** of `id` to `None` with the argument `default=None` in `Field()`:\n\n```Python\nField(default=None)\n```\n\nIf we didn't set the `default` value, whenever we use this model later to do data validation (powered by Pydantic) it would *accept* a value of `None` apart from an `int`, but it would still **require** passing that `None` value. And it would be confusing for whoever is using this model later (probably us), so **better set the default value here**.\n\n## Create the Engine\n\nNow we need to create the SQLAlchemy **Engine**.\n\nIt is an object that handles the communication with the database.\n\nIf you have a server database (for example PostgreSQL or MySQL), the **engine** will hold the **network connections** to that database.\n\nCreating the **engine** is very simple, just call `create_engine()` with a URL for the database to use:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:16] hl[1,14] *}\n\nYou should normally have a single **engine** object for your whole application and re-use it everywhere.\n\n/// tip\n\nThere's another related thing called a **Session** that normally should *not* be a single object per application.\n\nBut we will talk about it later.\n\n///\n\n### Engine Database URL\n\nEach supported database has its own URL type. For example, for **SQLite** it is `sqlite:///` followed by the file path. For example:\n\n* `sqlite:///database.db`\n* `sqlite:///databases/local/application.db`\n* `sqlite:///db.sqlite`\n\nSQLite supports a special database that lives all *in memory*. Hence, it's very fast, but be careful, the database gets deleted after the program terminates. You can specify this in-memory database by using just two slash characters (`//`) and no file name:\n\n* `sqlite://`\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:16] hl[11:12,14] *}\n\nYou can read a lot more about all the databases supported by **SQLAlchemy** (and that way supported by **SQLModel**) in the <a href=\"https://docs.sqlalchemy.org/en/14/core/engines.html\" class=\"external-link\" target=\"_blank\">SQLAlchemy documentation</a>.\n\n### Engine Echo\n\nIn this example, we are also using the argument `echo=True`.\n\nIt will make the engine print all the SQL statements it executes, which can help you understand what's happening.\n\nIt is particularly useful for **learning** and **debugging**:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:16] hl[14] *}\n\nBut in production, you would probably want to remove `echo=True`:\n\n```Python\nengine = create_engine(sqlite_url)\n```\n\n### Engine Technical Details\n\n/// tip\n\nIf you didn't know about SQLAlchemy before and are just learning **SQLModel**, you can probably skip this section, scroll below.\n\n///\n\nYou can read a lot more about the engine in the <a href=\"https://docs.sqlalchemy.org/en/14/tutorial/engine.html\" class=\"external-link\" target=\"_blank\">SQLAlchemy documentation</a>.\n\n**SQLModel** defines its own `create_engine()` function. It is the same as SQLAlchemy's `create_engine()`, but with the difference that it defaults to use `future=True` (which means that it uses the style of the latest SQLAlchemy, 1.4, and the future 2.0).\n\nAnd SQLModel's version of `create_engine()` is type annotated internally, so your editor will be able to help you with autocompletion and inline errors.\n\n## Create the Database and Table\n\nNow everything is in place to finally create the database and table:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py hl[16] *}\n\n/// tip\n\nCreating the engine doesn't create the `database.db` file.\n\nBut once we run `SQLModel.metadata.create_all(engine)`, it creates the `database.db` file **and** creates the `hero` table in that database.\n\nBoth things are done in this single step.\n\n///\n\nLet's unwrap that:\n\n```Python\nSQLModel.metadata.create_all(engine)\n```\n\n### SQLModel MetaData\n\nThe `SQLModel` class has a `metadata` attribute. It is an instance of a class `MetaData`.\n\nWhenever you create a class that inherits from `SQLModel` **and is configured with `table = True`**, it is registered in this `metadata` attribute.\n\nSo, by the last line, `SQLModel.metadata` already has the `Hero` registered.\n\n### Calling `create_all()`\n\nThis `MetaData` object at `SQLModel.metadata` has a `create_all()` method.\n\nIt takes an **engine** and uses it to create the database and all the tables registered in this `MetaData` object.\n\n### SQLModel MetaData Order Matters\n\nThis also means that you have to call `SQLModel.metadata.create_all()` *after* the code that creates new model classes inheriting from `SQLModel`.\n\nFor example, let's imagine you do this:\n\n* Create the models in one Python file `models.py`.\n* Create the engine object in a file `db.py`.\n* Create your main app and call `SQLModel.metadata.create_all()` in `app.py`.\n\nIf you only imported `SQLModel` and tried to call `SQLModel.metadata.create_all()` in `app.py`, it would not create your tables:\n\n```Python\n# This wouldn't work! 🚨\nfrom sqlmodel import SQLModel\n\nfrom .db import engine\n\nSQLModel.metadata.create_all(engine)\n```\n\nIt wouldn't work because when you import `SQLModel` alone, Python doesn't execute all the code creating the classes inheriting from it (in our example, the class `Hero`), so `SQLModel.metadata` is still empty.\n\nBut if you import the models *before* calling `SQLModel.metadata.create_all()`, it will work:\n\n```Python\nfrom sqlmodel import SQLModel\n\nfrom . import models\nfrom .db import engine\n\nSQLModel.metadata.create_all(engine)\n```\n\nThis would work because by importing the models, Python executes all the code creating the classes inheriting from `SQLModel` and registering them in the `SQLModel.metadata`.\n\nAs an alternative, you could import `SQLModel` and your models inside of `db.py`:\n\n```Python\n# db.py\nfrom sqlmodel import SQLModel, create_engine\nfrom . import models\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url)\n```\n\nAnd then import `SQLModel` *from* `db.py` in `app.py`, and there call `SQLModel.metadata.create_all()`:\n\n```Python\n# app.py\nfrom .db import engine, SQLModel\n\nSQLModel.metadata.create_all(engine)\n```\n\nThe import of `SQLModel` from `db.py` would work because `SQLModel` is also imported in `db.py`.\n\nAnd this trick would work correctly and create the tables in the database because by importing `SQLModel` from `db.py`, Python executes all the code creating the classes that inherit from `SQLModel` in that `db.py` file, for example, the class `Hero`.\n\n## Migrations\n\nFor this simple example, and for most of the **Tutorial - User Guide**, using `SQLModel.metadata.create_all()` is enough.\n\nBut for a production system you would probably want to use a system to migrate the database.\n\nThis would be useful and important, for example, whenever you add or remove a column, add a new table, change a type, etc.\n\nBut you will learn about migrations later in the Advanced User Guide.\n\n## Run The Program\n\nLet's run the program to see it all working.\n\nPut the code in a file `app.py` if you haven't already.\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py *}\n\n/// tip\n\nRemember to [activate the virtual environment](../virtual-environments.md#create-a-virtual-environment){.internal-link target=_blank} before running it.\n\n///\n\nNow run the program with Python:\n\n<div class=\"termy\">\n\n```console\n// We set echo=True, so this will show the SQL code\n$ python app.py\n\n// First, some boilerplate SQL that we are not that interested in\n\nINFO Engine BEGIN (implicit)\nINFO Engine PRAGMA main.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine PRAGMA temp.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine\n\n// Finally, the glorious SQL to create the table ✨\n\nCREATE TABLE hero (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        PRIMARY KEY (id)\n)\n\n// More SQL boilerplate\n\nINFO Engine [no key 0.00020s] ()\nINFO Engine COMMIT\n```\n\n</div>\n\n/// info\n\nI simplified the output above a bit to make it easier to read.\n\nBut in reality, instead of showing:\n\n```\nINFO Engine BEGIN (implicit)\n```\n\nit would show something like:\n\n```\n2021-07-25 21:37:39,175 INFO sqlalchemy.engine.Engine BEGIN (implicit)\n```\n\n///\n\n### `TEXT` or `VARCHAR`\n\nIn the example in the previous chapter we created the table using `TEXT` for some columns.\n\nBut in this output SQLAlchemy is using `VARCHAR` instead. Let's see what's going on.\n\nRemember that [each SQL Database has some different variations in what they support?](../databases.md#sql-the-language){.internal-link target=_blank}\n\nThis is one of the differences. Each database supports some particular **data types**, like `INTEGER` and `TEXT`.\n\nSome databases have some particular types that are special for certain things. For example, PostgreSQL and MySQL support `BOOLEAN` for values of `True` and `False`. SQLite accepts SQL with booleans, even when defining table columns, but what it actually uses internally are `INTEGER`s, with `1` to represent `True` and `0` to represent `False`.\n\nThe same way, there are several possible types for storing strings. SQLite uses the `TEXT` type. But other databases like PostgreSQL and MySQL use the `VARCHAR` type by default, and `VARCHAR` is one of the most common data types.\n\n**`VARCHAR`** comes from **variable** length **character**.\n\nSQLAlchemy generates the SQL statements to create tables using `VARCHAR`, and then SQLite receives them, and internally converts them to `TEXT`s.\n\nAdditional to the difference between those two data types, some databases like MySQL require setting a maximum length for the `VARCHAR` types, for example `VARCHAR(255)` sets the maximum number of characters to 255.\n\nTo make it easier to start using **SQLModel** right away independent of the database you use (even with MySQL), and without any extra configurations, by default, `str` fields are interpreted as `VARCHAR` in most databases and `VARCHAR(255)` in MySQL, this way you know the same class will be compatible with the most popular databases without extra effort.\n\n/// tip\n\nYou will learn how to change the maximum length of string columns later in the Advanced Tutorial - User Guide.\n\n///\n\n### Verify the Database\n\nNow, open the database with **DB Browser for SQLite**, you will see that the program created the table `hero` just as before. 🎉\n\n<img class=\"shadow\" src=\"/img/create-db-and-table-with-db-browser/image008.png\">\n\n## Refactor Data Creation\n\nNow let's restructure the code a bit to make it easier to **reuse**, **share**, and **test** later.\n\nLet's move the code that has the main **side effects**, that changes data (creates a file with a database and a table) to a function.\n\nIn this example it's just the `SQLModel.metadata.create_all(engine)`.\n\nLet's put it in a function `create_db_and_tables()`:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial002_py310.py ln[1:18] hl[17:18] *}\n\nIf `SQLModel.metadata.create_all(engine)` was not in a function and we tried to import something from this module (from this file) in another, it would try to create the database and table **every time** we executed that other file that imported this module.\n\nWe don't want that to happen like that, only when we **intend** it to happen, that's why we put it in a function, because we can make sure that the tables are created only when we call that function, and not when this module is imported somewhere else.\n\nNow we would be able to, for example, import the `Hero` class in some other file without having those **side effects**.\n\n/// tip\n\n😅 **Spoiler alert**: The function is called `create_db_and_tables()` because we will have more **tables** in the future with other classes apart from `Hero`. 🚀\n\n///\n\n### Create Data as a Script\n\nWe prevented the side effects when importing something from your `app.py` file.\n\nBut we still want it to **create the database and table** when we call it with Python directly as an independent script from the terminal, just as above.\n\n/// tip\n\nThink of the word **script** and **program** as interchangeable.\n\nThe word **script** often implies that the code could be run independently and easily. Or in some cases it refers to a relatively simple program.\n\n///\n\nFor that we can use the special variable `__name__` in an `if` block:\n\n{* ./docs_src/tutorial/create_db_and_table/tutorial002_py310.py hl[21:22] *}\n\n### About `__name__ == \"__main__\"`\n\nThe main purpose of the `__name__ == \"__main__\"` is to have some code that is executed when your file is called with:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Something happens here ✨\n```\n\n</div>\n\n...but is not called when another file imports it, like in:\n\n```Python\nfrom app import Hero\n```\n\n/// tip\n\nThat `if` block using `if __name__ == \"__main__\":` is sometimes called the \"**main block**\".\n\nThe official name (in the <a href=\"https://docs.python.org/3/library/__main__.html\" class=\"external-link\" target=\"_blank\">Python docs</a>) is \"**Top-level script environment**\".\n\n///\n\n#### More details\n\nLet's say your file is named `myapp.py`.\n\nIf you run it with:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n\n// This will call create_db_and_tables()\n```\n\n</div>\n\n...then the internal variable `__name__` in your file, created automatically by Python, will have as value the string `\"__main__\"`.\n\nSo, the function in:\n\n```Python hl_lines=\"2\"\nif __name__ == \"__main__\":\n    create_db_and_tables()\n```\n\n...will run.\n\n---\n\nThis won't happen if you import that module (file).\n\nSo, if you have another file `importer.py` with:\n\n```Python\nfrom myapp import Hero\n\n# Some more code\n```\n\n...in that case, the automatic variable inside of `myapp.py` will not have the variable `__name__` with a value of `\"__main__\"`.\n\nSo, the line:\n\n```Python hl_lines=\"2\"\nif __name__ == \"__main__\":\n    create_db_and_tables()\n```\n\n...will **not** be executed.\n\n/// info\n\nFor more information, check <a href=\"https://docs.python.org/3/library/__main__.html\" class=\"external-link\" target=\"_blank\">the official Python docs</a>.\n\n///\n\n## Last Review\n\nAfter those changes, you could run it again, and it would generate the same output as before.\n\nBut now we can import things from this module in other files.\n\nNow, let's give the code a final look:\n\n//// tab | Python 3.10+\n\n```{.python .annotate}\n{!./docs_src/tutorial/create_db_and_table/tutorial003_py310.py!}\n```\n\n{!./docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md!}\n\n////\n\n/// tip\n\nReview what each line does by clicking each number bubble in the code. 👆\n\n///\n\n## Recap\n\nWe learnt how to use **SQLModel** to define how a table in the database should look like, and we created a database and a table using **SQLModel**.\n\nWe also refactored the code to make it easier to reuse, share, and test later.\n\nIn the next chapters we will see how **SQLModel** will help us interact with SQL databases from code. 🤓\n"
  },
  {
    "path": "docs/tutorial/delete.md",
    "content": "# Delete Data - DELETE\n\nNow let's delete some data using **SQLModel**.\n\n## Continue From Previous Code\n\nAs before, we'll continue from where we left off with the previous code.\n\n{* ./docs_src/tutorial/update/tutorial003_py310.py ln[0] *}\n\nRemember to remove the `database.db` file before running the examples to get the same results.\n\n## Delete with SQL\n\nThis `Spider-Youngster` is getting too weird, so let's just delete it.\n\nBut don't worry, we'll reboot it later with a new story. 😅\n\nLet's see how to delete it with **SQL**:\n\n```SQL hl_lines=\"1\"\nDELETE\nFROM hero\nWHERE name = \"Spider-Youngster\"\n```\n\nThis means, more or less:\n\n> Hey SQL database 👋, I want to `DELETE` rows `FROM` the table called `hero`.\n>\n> Please delete all the rows `WHERE` the value of the column `name` is equal to `\"Spider-Youngster\"`.\n\nRemember that when using a `SELECT` statement it has the form:\n\n```SQL\nSELECT [some stuff here]\nFROM [name of a table here]\nWHERE [some condition here]\n```\n\n`DELETE` is very similar, and again we use `FROM` to tell the table to work on, and we use `WHERE` to tell the condition to use to match the rows that we want to delete.\n\nYou can try that in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/delete/image01.png\">\n\nHave in mind that `DELETE` is to delete entire **rows**, not single values in a row.\n\nIf you want to \"delete\" a single value in a column while **keeping the row**, you would instead **update** the row as explained in the previous chapter, setting the specific value of the column in that row to `NULL` (to `None` in Python).\n\nNow let's delete with **SQLModel**.\n\nTo get the same results, delete the `database.db` file before running the examples.\n\n## Read From the Database\n\nWe'll start by selecting the hero `\"Spider-Youngster\"` that we updated in the previous chapter, this is the one we will delete:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:75] hl[72] *}\n\nAs this is a new function `delete_heroes()`, we'll also add it to the `main()` function so that we call it when executing the program from the command line:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[90:98] hl[94] *}\n\nThat will print the same existing hero **Spider-Youngster**:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00011s] ('Spider-Youngster',)\n\n// Print the hero as obtained from the database\nHero:  name='Spider-Youngster' secret_name='Pedro Parqueador' age=16 id=2\n```\n\n</div>\n\n## Delete the Hero from the Session\n\nNow, very similar to how we used `session.add()` to add or update new heroes, we can use `session.delete()` to delete the hero from the session:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:77] hl[77] *}\n\n## Commit the Session\n\nTo save the current changes in the session, **commit** it.\n\nThis will save all the changes stored in the **session**, like the deleted hero:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:78] hl[78] *}\n\nThe same as we have seen before, `.commit()` will also save anything else that was added to the session. Including updates, or created heroes.\n\nThis commit after deleting the hero will generate this output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// The SQL to update the hero in the database\nINFO Engine DELETE FROM hero WHERE hero.id = ?\nINFO Engine [generated in 0.00020s] (2,)\nINFO Engine COMMIT\n```\n\n</div>\n\n## Print the Deleted Object\n\nNow the hero is deleted from the database.\n\nIf we tried to use `session.refresh()` with it, it would raise an exception, because there's no data in the database for this hero.\n\nNevertheless, the object is still available with its data, but now it's not connected to the session and it no longer exists in the database.\n\nAs the object is not connected to the session, it is not marked as \"expired\", the session doesn't even care much about this object anymore.\n\nBecause of that, the object still contains its attributes with the data in it, so we can print it:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:80] hl[80] *}\n\nThis will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// Print the deleted hero\nDeleted hero: name='Spider-Youngster' secret_name='Pedro Parqueador' age=16 id=2\n```\n\n</div>\n\n## Query the Database for the Same Row\n\nTo confirm if it was deleted, now let's query the database again, with the same `\"Spider-Youngster\"` name:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:84] hl[82:84] *}\n\nHere we are using `results.first()` to get the first object found (in case it found multiple) or `None`, if it didn't find anything.\n\nIf we used `results.one()` instead, it would raise an exception, because it expects exactly one result.\n\nAnd because we just deleted that hero, this should not find anything and we should get `None`.\n\nThis will execute some SQL in the database and output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// SQL to search for the hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00013s] ('Spider-Youngster',)\n```\n\n</div>\n\n## Confirm the Deletion\n\nNow let's just confirm that, indeed, no hero was found in the database with that name.\n\nWe'll do it by checking that the \"first\" item in the `results` is `None`:\n\n{* ./docs_src/tutorial/delete/tutorial001_py310.py ln[70:87] hl[86:87] *}\n\nThis will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// Indeed, the hero was deleted 🔥\nThere's no hero named Spider-Youngster\n\n// Cleanup after the with block\nINFO Engine ROLLBACK\n```\n\n</div>\n\n## Review the Code\n\nNow let's review all that code:\n\n//// tab | Python 3.10+\n\n```{ .python .annotate hl_lines=\"70-88\" }\n{!./docs_src/tutorial/delete/tutorial002_py310.py!}\n```\n\n{!./docs_src/tutorial/delete/annotations/en/tutorial002.md!}\n\n////\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\n## Recap\n\nTo delete rows with **SQLModel** you just have to `.delete()` them with the **session**, and then, as always, `.commit()` the session to save the changes to the database. 🔥\n"
  },
  {
    "path": "docs/tutorial/fastapi/delete.md",
    "content": "# Delete Data with FastAPI\n\nLet's now add a *path operation* to delete a hero.\n\nThis is quite straightforward. 😁\n\n## Delete Path Operation\n\nBecause we want to **delete** data, we use an HTTP `DELETE` operation.\n\nWe get a `hero_id` from the path parameter and verify if it exists, just as we did when reading a single hero or when updating it, **possibly raising an error** with a `404` response.\n\nAnd if we actually find a hero, we just delete it with the **session**.\n\n{* ./docs_src/tutorial/fastapi/delete/tutorial001_py310.py ln[89:97] hl[89:97] *}\n\nAfter deleting it successfully, we just return a response of:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n## Recap\n\nThat's it, feel free to try it out in the interactive docs UI to delete some heroes. 💥\n\nUsing **FastAPI** to read data and combining it with **SQLModel** makes it quite straightforward to delete data from the database.\n"
  },
  {
    "path": "docs/tutorial/fastapi/index.md",
    "content": "# FastAPI and Pydantic - Intro\n\nOne of the use cases where **SQLModel** shines the most, and the main one why it was built, was to be combined with **FastAPI**. ✨\n\n<a href=\"https://fastapi.tiangolo.com/\" class=\"external-link\" target=\"_blank\">FastAPI</a> is a Python web framework for building web APIs created by the same <a href=\"https://twitter.com/tiangolo\" class=\"external-link\" target=\"_blank\">author</a> of SQLModel. FastAPI is also built on top of **Pydantic**.\n\nIn this group of chapters we will see how to combine SQLModel **table models** representing tables in the SQL database as all the ones we have seen up to now, with **data models** that only represent data (which are actually just Pydantic models behind the scenes).\n\nBeing able to combine SQLModel **table** models with pure **data** models would be useful on its own, but to make all the examples more concrete, we will use them with **FastAPI**.\n\nBy the end we will have a **simple** but **complete** web **API** to interact with the data in the database. 🎉\n\n## Learning FastAPI\n\nIf you have never used FastAPI, maybe a good idea would be to go and study it a bit before continuing.\n\nJust reading and trying the examples on the <a href=\"https://fastapi.tiangolo.com/\" class=\"external-link\" target=\"_blank\">FastAPI main page</a> should be enough, and it shouldn't take you more than **10 minutes**.\n"
  },
  {
    "path": "docs/tutorial/fastapi/limit-and-offset.md",
    "content": "# Read Heroes with Limit and Offset with FastAPI\n\nWhen a client sends a request to get all the heroes, we have been returning them all.\n\nBut if we had **thousands** of heroes that could consume a lot of **computational resources**, network bandwidth, etc.\n\nSo, we probably want to limit it.\n\nLet's use the same **offset** and **limit** we learned about in the previous tutorial chapters for the API.\n\n/// info\n\nIn many cases, this is also called **pagination**.\n\n///\n\n## Add a Limit and Offset to the Query Parameters\n\nLet's add `limit` and `offset` to the query parameters.\n\nBy default, we will return the first results from the database, so `offset` will have a default value of `0`.\n\nAnd by default, we will return a maximum of `100` heroes, so `limit` will have a default value of `100`.\n\n{* ./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py310.py ln[1:2,52:56] hl[1,53,55] *}\n\nWe want to allow clients to set different `offset` and `limit` values.\n\nBut we don't want them to be able to set a `limit` of something like `9999`, that's over `9000`! 😱\n\nSo, to prevent it, we add additional validation to the `limit` query parameter, declaring that it has to be **l**ess than or **e**qual to `100` with `le=100`.\n\nThis way, a client can decide to take fewer heroes if they want, but not more.\n\n/// info\n\nIf you need to refresh how query parameters and their validation work, check out the docs in FastAPI:\n\n* <a href=\"https://fastapi.tiangolo.com/tutorial/query-params/\" class=\"external-link\" target=\"_blank\">Query Parameters</a>\n* <a href=\"https://fastapi.tiangolo.com/tutorial/query-params-str-validations/\" class=\"external-link\" target=\"_blank\">Query Parameters and String Validations</a>\n* <a href=\"https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/\" class=\"external-link\" target=\"_blank\">Path Parameters and Numeric Validations</a>\n\n///\n\n## Check the Docs UI\n\nNow we can see that the docs UI shows the new parameters to control **limit** and **offset** of our data.\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/limit-and-offset/image01.png\">\n\n## Recap\n\nYou can use **FastAPI**'s automatic data validation to get the parameters for `limit` and `offset`, and then use them with the **session** to control ranges of data to be sent in responses.\n"
  },
  {
    "path": "docs/tutorial/fastapi/multiple-models.md",
    "content": "# Multiple Models with FastAPI\n\nWe have been using the same `Hero` model to declare the schema of the data we receive in the API, the table model in the database, and the schema of the data we send back in responses.\n\nBut in most of the cases, there are slight differences. Let's use multiple models to solve it.\n\nHere you will see the main and biggest feature of **SQLModel**. 😎\n\n## Review Creation Schema\n\nLet's start by reviewing the automatically generated schemas from the docs UI.\n\nFor input, we have:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/simple-hero-api/image01.png\">\n\nIf we pay attention, it shows that the client *could* send an `id` in the JSON body of the request.\n\nThis means that the client could try to use the same ID that already exists in the database to create another hero.\n\nThat's not what we want.\n\nWe want the client only to send the data that is needed to create a new hero:\n\n* `name`\n* `secret_name`\n* Optional `age`\n\nAnd we want the `id` to be generated automatically by the database, so we don't want the client to send it.\n\nWe'll see how to fix it in a bit.\n\n## Review Response Schema\n\nNow let's review the schema of the response we send back to the client in the docs UI.\n\nIf you click the small tab <kbd>Schema</kbd> instead of the <kbd>Example Value</kbd>, you will see something like this:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/multiple-models/image01.png\">\n\nLet's see the details.\n\nThe fields with a red asterisk (<span style=\"color: #ff0000;\">*</span>) are \"required\".\n\nThis means that our API application is required to return those fields in the response:\n\n* `name`\n* `secret_name`\n\nThe `age` is optional, we don't have to return it, or it could be `None` (or `null` in JSON), but the `name` and the `secret_name` are required.\n\nHere's the weird thing, the `id` currently seems also \"optional\". 🤔\n\nThis is because in our **SQLModel** class we declare the `id` with a default value of `= None`, because it could be `None` in memory until we save it in the database and we finally get the actual ID.\n\nBut in the responses, we always send a model from the database, so it **always has an ID**. So the `id` in the responses can be declared as required.\n\nThis means that our application is making the promise to the clients that if it sends a hero, it will for sure have an `id` with a value, it will not be `None`.\n\n### Why Is it Important to Have a Contract for Responses\n\nThe ultimate goal of an API is for some **clients to use it**.\n\nThe clients could be a frontend application, a command line program, a graphical user interface, a mobile application, another backend application, etc.\n\nAnd the code those clients write depends on what our API tells them they **need to send**, and what they can **expect to receive**.\n\nMaking both sides very clear will make it much easier to interact with the API.\n\nAnd in most of the cases, the developer of the client for that API **will also be yourself**, so you are **doing your future self a favor** by declaring those schemas for requests and responses. 😉\n\n### So Why is it Important to Have Required IDs\n\nNow, what's the matter with having one **`id` field marked as \"optional\"** in a response when in reality it is always available (required)?\n\nFor example, **automatically generated clients** in other languages (or also in Python) would have some declaration that this field `id` is optional.\n\nAnd then the developers using those clients in their languages would have to be checking all the time in all their code if the `id` is not `None` before using it anywhere.\n\nThat's a lot of unnecessary checks and **unnecessary code** that could have been saved by declaring the schema properly. 😔\n\nIt would be a lot simpler for that code to know that the `id` from a response is required and **will always have a value**.\n\nLet's fix that too. 🤓\n\n## Multiple Hero Schemas\n\nSo, we want to have our `Hero` model that declares the **data in the database**:\n\n* `id`, optional on creation, required on database\n* `name`, required\n* `secret_name`, required\n* `age`, optional\n\nBut we also want to have a `HeroCreate` for the data we want to receive when **creating** a new hero, which is almost all the same data as `Hero`, except for the `id`, because that is created automatically by the database:\n\n* `name`, required\n* `secret_name`, required\n* `age`, optional\n\nAnd we want to have a `HeroPublic` with the `id` field, but this time with a type of `id: int`, instead of `id: int | None`, to make it clear that it will always have an `int` in responses **read** from the clients:\n\n* `id`, required\n* `name`, required\n* `secret_name`, required\n* `age`, optional\n\n## Multiple Models with Duplicated Fields\n\nThe simplest way to solve it could be to create **multiple models**, each one with all the corresponding fields:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[5:22] hl[5:9,12:15,18:22] *}\n\nHere's the important detail, and probably the most important feature of **SQLModel**: only `Hero` is declared with `table = True`.\n\nThis means that the class `Hero` represents a **table** in the database. It is both a **Pydantic** model and a **SQLAlchemy** model.\n\nBut `HeroCreate` and `HeroPublic` don't have `table = True`. They are only **data models**, they are only **Pydantic** models. They won't be used with the database, but only to declare data schemas for the API (or for other uses).\n\nThis also means that `SQLModel.metadata.create_all()` won't create tables in the database for `HeroCreate` and `HeroPublic`, because they don't have `table = True`, which is exactly what we want. 🚀\n\n/// tip\n\nWe will improve this code to avoid duplicating the fields, but for now we can continue learning with these models.\n\n///\n\n## Use Multiple Models to Create a Hero\n\nLet's now see how to use these new models in the FastAPI application.\n\nLet's first check how is the process to create a hero now:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[44:51] hl[44:45,47] *}\n\nLet's check that in detail.\n\nNow we use the type annotation `HeroCreate` for the request JSON data in the `hero` parameter of the **path operation function**.\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[45] hl[45] *}\n\nThen we create a new `Hero` (this is the actual **table** model that saves things to the database) using `Hero.model_validate()`.\n\nThe method `.model_validate()` reads data from another object with attributes (or a dict) and creates a new instance of this class, in this case `Hero`.\n\nIn this case, we have a `HeroCreate` instance in the `hero` variable. This is an object with attributes, so we use `.model_validate()` to read those attributes.\n\n/// tip\nIn versions of **SQLModel** before `0.0.14` you would use the method `.from_orm()`, but it is now deprecated and you should use `.model_validate()` instead.\n///\n\nWe can now create a new `Hero` instance (the one for the database) and put it in the variable `db_hero` from the data in the `hero` variable that is the `HeroCreate` instance we received from the request.\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[47] hl[47] *}\n\nThen we just `add` it to the **session**, `commit`, and `refresh` it, and finally, we return the same `db_hero` variable that has the just refreshed `Hero` instance.\n\nBecause it is just refreshed, it has the `id` field set with a new ID taken from the database.\n\nAnd now that we return it, FastAPI will validate the data with the `response_model`, which is a `HeroPublic`:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[44] hl[44] *}\n\nThis will validate that all the data that we promised is there and will remove any data we didn't declare.\n\n/// tip\n\nThis filtering could be very important and could be a very good security feature, for example, to make sure you filter private data, hashed passwords, etc.\n\nYou can read more about it in the <a href=\"https://fastapi.tiangolo.com/tutorial/response-model/\" class=\"external-link\" target=\"_blank\">FastAPI docs about Response Model</a>.\n\n///\n\nIn particular, it will make sure that the `id` is there and that it is indeed an integer (and not `None`).\n\n## Shared Fields\n\nBut looking closely, we could see that these models have a lot of **duplicated information**.\n\nAll **the 3 models** declare that they share some **common fields** that look exactly the same:\n\n* `name`, required\n* `secret_name`, required\n* `age`, optional\n\nAnd then they declare other fields with some differences (in this case, only about the `id`).\n\nWe want to **avoid duplicated information** if possible.\n\nThis is important if, for example, in the future, we decide to **refactor the code** and rename one field (column). For example, from `secret_name` to `secret_identity`.\n\nIf we have that duplicated in multiple models, we could easily forget to update one of them. But if we **avoid duplication**, there's only one place that would need updating. ✨\n\nLet's now improve that. 🤓\n\n## Multiple Models with Inheritance\n\nAnd here it is, you found the biggest feature of **SQLModel**. 💎\n\nEach of these models is only a **data model** or both a data model and a **table model**.\n\nSo, it's possible to create models with **SQLModel** that don't represent tables in the database.\n\nOn top of that, we can use inheritance to avoid duplicated information in these models.\n\nWe can see from above that they all share some **base** fields:\n\n* `name`, required\n* `secret_name`, required\n* `age`, optional\n\nSo let's create a **base** model `HeroBase` that the others can inherit from:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:8] hl[5:8] *}\n\nAs you can see, this is *not* a **table model**, it doesn't have the `table = True` config.\n\nBut now we can create the **other models inheriting from it**, they will all share these fields, just as if they had them declared.\n\n### The `Hero` **Table Model**\n\nLet's start with the only **table model**, the `Hero`:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:12] hl[11:12] *}\n\nNotice that `Hero` now doesn't inherit from `SQLModel`, but from `HeroBase`.\n\nAnd now we only declare one single field directly, the `id`, that here is `int | None`, and is a `primary_key`.\n\nAnd even though we don't declare the other fields **explicitly**, because they are inherited, they are also part of this `Hero` model.\n\nAnd of course, all these fields will be in the columns for the resulting `hero` table in the database.\n\nAnd those inherited fields will also be in the **autocompletion** and **inline errors** in editors, etc.\n\n### Columns and Inheritance with Multiple Models\n\nNotice that the parent model `HeroBase`  is not a **table model**, but still, we can declare `name` and `age` using `Field(index=True)`.\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:12] hl[6,8,11] *}\n\nThis won't affect this parent **data model** `HeroBase`.\n\nBut once the child model `Hero` (the actual **table model**) inherits those fields, it will use those field configurations to create the indexes when creating the tables in the database.\n\n### The `HeroCreate` **Data Model**\n\nNow let's see the `HeroCreate` model that will be used to define the data that we want to receive in the API when creating a new hero.\n\nThis is a fun one:\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:16] hl[15:16] *}\n\nWhat's happening here?\n\nThe fields we need to create are **exactly the same** as the ones in the `HeroBase` model. So we don't have to add anything.\n\nAnd because we can't leave the empty space when creating a new class, but we don't want to add any field, we just use `pass`.\n\nThis means that there's nothing else special in this class apart from the fact that it is named `HeroCreate` and that it inherits from `HeroBase`.\n\nAs an alternative, we could use `HeroBase` directly in the API code instead of `HeroCreate`, but it would show up in the automatic docs UI with that name \"`HeroBase`\" which could be **confusing** for clients. Instead, \"`HeroCreate`\" is a bit more explicit about what it is for.\n\nOn top of that, we could easily decide in the future that we want to receive **more data** when creating a new hero apart from the data in `HeroBase` (for example, a password), and now we already have the class to put those extra fields.\n\n### The `HeroPublic` **Data Model**\n\nNow let's check the `HeroPublic` model.\n\nThis one just declares that the `id` field is required when reading a hero from the API, because a hero read from the API will come from the database, and in the database it will always have an ID.\n\n{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:20] hl[19:20] *}\n\n## Review the Updated Docs UI\n\nThe FastAPI code is still the same as above, we still use `Hero`, `HeroCreate`, and `HeroPublic`. But now, we define them in a smarter way with inheritance.\n\nSo, we can jump to the docs UI right away and see how they look with the updated data.\n\n### Docs UI to Create a Hero\n\nLet's see the new UI for creating a hero:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/multiple-models/image02.png\">\n\nNice! It now shows that to create a hero, we just pass the `name`, `secret_name`, and optionally `age`.\n\nWe no longer pass an `id`.\n\n### Docs UI with Hero Responses\n\nNow we can scroll down a bit to see the response schema:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/multiple-models/image03.png\">\n\nWe can now see that `id` is a required field, it has a red asterisk (<span style=\"color: #f00;\">*</span>).\n\nAnd if we check the schema for the **Read Heroes** *path operation* it will also show the updated schema.\n\n## Inheritance and Table Models\n\nWe just saw how powerful the inheritance of these models could be.\n\nThis is a very simple example, and it might look a bit... meh. 😅\n\nBut now imagine that your table has **10 or 20 columns**. And that you have to duplicate all that information for all your **data models**... then it becomes more obvious why it's quite useful to be able to avoid all that information duplication with inheritance.\n\nNow, this probably looks so flexible that it's not obvious **when to use inheritance** and for what.\n\nHere are a couple of rules of thumb that can help you.\n\n### Only Inherit from Data Models\n\nOnly inherit from **data models**, don't inherit from **table models**.\n\nIt will help you avoid confusion, and there won't be any reason for you to need to inherit from a **table model**.\n\nIf you feel like you need to inherit from a **table model**, then instead create a **base** class that is only a **data model** and has all those fields, like `HeroBase`.\n\nAnd then inherit from that **base** class that is only a **data model** for any other **data model** and for the **table model**.\n\n### Avoid Duplication - Keep it Simple\n\nIt could feel like you need to have a profound reason why to inherit from one model or another, because \"in some mystical way\" they separate different concepts... or something like that.\n\nIn some cases, there are **simple separations** that you can use, like the models to create data, read, update, etc. If that's quick and obvious, nice, use it. 💯\n\nOtherwise, don't worry too much about profound conceptual reasons to separate models, just try to **avoid duplication** and **keep the code simple** enough to reason about it.\n\nIf you see you have a lot of **overlap** between two models, then you can probably **avoid some of that duplication** with a base model.\n\nBut if to avoid some duplication you end up with a crazy tree of models with inheritance, then it might be **simpler** to just duplicate some of those fields, and that might be easier to reason about and to maintain.\n\nDo whatever is easier to **reason** about, to **program** with, to **maintain**, and to **refactor** in the future. 🤓\n\nRemember that inheritance, the same as **SQLModel**, and anything else, are just tools to **help you be more productive**, that's one of their main objectives. If something is not helping with that (e.g. too much duplication, too much complexity), then change it. 🚀\n\n## Recap\n\nYou can use **SQLModel** to declare multiple models:\n\n* Some models can be only **data models**. They will also be **Pydantic** models.\n* And some can *also* be **table models** (apart from already being **data models**) by having the config `table = True`. They will also be **Pydantic** models and **SQLAlchemy** models.\n\nOnly the **table models** will create tables in the database.\n\nSo, you can use all the other **data models** to validate, convert, filter, and document the schema of the data for your application. ✨\n\nYou can use inheritance to **avoid information and code duplication**. 😎\n\nAnd you can use all these models directly with **FastAPI**. 🚀\n"
  },
  {
    "path": "docs/tutorial/fastapi/read-one.md",
    "content": "# Read One Model with FastAPI\n\nLet's now add a *path operation* to read a single model to our **FastAPI** application.\n\n## Path Operation for One Hero\n\nLet's add a new *path operation* to read one single hero.\n\nWe want to get the hero based on the `id`, so we will use a **path parameter** `hero_id`.\n\n/// info\n\nIf you need to refresh how *path parameters* work, including their data validation, check the <a href=\"https://fastapi.tiangolo.com/tutorial/path-params/\" class=\"external-link\" target=\"_blank\">FastAPI docs about Path Parameters</a>.\n\n///\n\n{* ./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py ln[1:2,59:65] hl[59] *}\n\nFor example, to get the hero with ID `2` we would send a `GET` request to:\n\n```\n/heroes/2\n```\n\n## Handling Errors\n\nThen, because FastAPI already takes care of making sure that the `hero_id` is an actual integer, we can use it directly with `Hero.get()` to try and get one hero by that ID.\n\nBut if the integer is not the ID of any hero in the database, it will not find anything, and the variable `hero` will be `None`.\n\nSo, we check it in an `if` block, if it's `None`, we raise an `HTTPException` with a `404` status code.\n\nAnd to use it, we first import `HTTPException` from `fastapi`.\n\nThis will let the client know that they probably made a mistake on their side and requested a hero that doesn't exist in the database.\n\n{* ./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py ln[1:2,59:65] hl[1,62:64] *}\n\n## Return the Hero\n\nThen, if the hero exists, we return it.\n\nAnd because we are using the `response_model` with `HeroPublic`, it will be validated, documented, etc.\n\n{* ./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py ln[1:2,59:65] hl[59,65] *}\n\n## Check the Docs UI\n\nWe can then go to the docs UI and see the new *path operation*.\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/read-one/image01.png\">\n\n## Recap\n\nYou can combine **FastAPI** features like automatic path parameter validation to get models by ID.\n"
  },
  {
    "path": "docs/tutorial/fastapi/relationships.md",
    "content": "# Models with Relationships in FastAPI\n\nIf we go right now and read a single **hero** by ID, we get the hero data with the team ID.\n\nBut we don't get any data about the particular team:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI getting a single hero\" src=\"/img/tutorial/fastapi/relationships/image01.png\">\n\nWe get a response of:\n\n```JSON hl_lines=\"5\"\n{\n    \"name\": \"Deadpond\",\n    \"secret_name\": \"Dive Wilson\",\n    \"age\": null,\n    \"team_id\": 1,\n    \"id\": 1,\n}\n```\n\nAnd the same way, if we get a **team** by ID, we get the team data, but we don't get any information about this team's heroes:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI getting a single team\" src=\"/img/tutorial/fastapi/relationships/image02.png\">\n\nHere we get a response of:\n\n```JSON\n{\n    \"name\": \"Preventers\",\n    \"headquarters\": \"Sharp Tower\",\n    \"id\": 2\n}\n```\n\n...but no information about the heroes.\n\nLet's update that. 🤓\n\n## Why Aren't We Getting More Data\n\nFirst, why is it that we are not getting the related data for each hero and for each team?\n\nIt's because we declared the `HeroPublic` with only the same base fields of the `HeroBase` plus the `id`. But it doesn't include a field `team` for the **relationship attribute**.\n\nAnd the same way, we declared the `TeamPublic` with only the same base fields of the `TeamBase` plus the `id`. But it doesn't include a field `heroes` for the **relationship attribute**.\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[5:7,20:21,29:34,43:44] hl[5:7,20:21,29:34,43:44] *}\n\nNow, remember that <a href=\"https://fastapi.tiangolo.com/tutorial/response-model/\" class=\"external-link\" target=\"_blank\">FastAPI uses the `response_model` to validate and **filter** the response data</a>?\n\nIn this case, we used `response_model=TeamPublic` and `response_model=HeroPublic`, so FastAPI will use them to filter the response data, even if we return a **table model** that includes **relationship attributes**:\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[102:107,155:160] hl[102,107,155,160] *}\n\n## Don't Include All the Data\n\nNow let's stop for a second and think about it.\n\nWe cannot simply include *all* the data, including all the internal relationships, because each **hero** has an attribute `team` with their team, and then that **team** also has an attribute `heroes` with all the **heroes** in the team, including this one.\n\nIf we tried to include everything, we could make the server application **crash** trying to extract **infinite data**, going through the same hero and team over and over again internally, something like this:\n\n```JSON hl_lines=\"2  13  24  34\"\n{\n    \"name\": \"Rusty-Man\",\n    \"secret_name\": \"Tommy Sharp\",\n    \"age\": 48,\n    \"team_id\": 1,\n    \"id\": 1,\n    \"team\": {\n        \"name\": \"Preventers\",\n        \"headquarters\": \"Sharp Tower\",\n        \"id\": 2,\n        \"heroes\": [\n            {\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"age\": 48,\n                \"team_id\": 1,\n                \"id\": 1,\n                \"team\": {\n                    \"name\": \"Preventers\",\n                    \"headquarters\": \"Sharp Tower\",\n                    \"id\": 2,\n                    \"heroes\": [\n                        {\n                            \"name\": \"Rusty-Man\",\n                            \"secret_name\": \"Tommy Sharp\",\n                            \"age\": 48,\n                            \"team_id\": 1,\n                            \"id\": 1,\n                            \"team\": {\n                                \"name\": \"Preventers\",\n                                \"headquarters\": \"Sharp Tower\",\n                                \"id\": 2,\n                                \"heroes\": [\n                                    ...with infinite data here... 😱\n                                ]\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}\n```\n\nAs you can see, in this example, we would get the hero **Rusty-Man**, and from this hero we would get the team **Preventers**, and then from this team we would get its heroes, of course, including **Rusty-Man**... 😱\n\nSo we start again, and in the end, the server would just crash trying to get all the data with a `\"Maximum recursion error\"`, we would not even get a response like the one above.\n\nSo, we need to carefully choose in which cases we want to include data and in which not.\n\n## What Data to Include\n\nThis is a decision that will depend on **each application**.\n\nIn our case, let's say that if we get a **list of heroes**, we don't want to also include each of their teams in each one.\n\nAnd if we get a **list of teams**, we don't want to get a list of the heroes for each one.\n\nBut if we get a **single hero**, we want to include the team data (without the team's heroes).\n\nAnd if we get a **single team**, we want to include the list of heroes (without each hero's team).\n\nLet's add a couple more **data models** that declare that data so we can use them in those two specific *path operations*.\n\n## Models with Relationships\n\nLet's add the models `HeroPublicWithTeam` and `TeamPublicWithHeroes`.\n\nWe'll add them **after** the other models so that we can easily reference the previous models.\n\n{* ./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py ln[59:64] hl[59:60,63:64] *}\n\nThese two models are very **simple in code**, but there's a lot happening here. Let's check it out.\n\n### Inheritance and Type Annotations\n\nThe `HeroPublicWithTeam` **inherits** from `HeroPublic`, which means that it will have the **normal fields for reading**, including the required `id` that was declared in `HeroPublic`.\n\nAnd then it adds the **new field** `team`, which could be `None`, and is declared with the type `TeamPublic` with the base fields for reading a team.\n\nThen we do the same for the `TeamPublicWithHeroes`, it **inherits** from `TeamPublic`, and declares the **new field** `heroes`, which is a list of `HeroPublic`.\n\n### Data Models Without Relationship Attributes\n\nNow, notice that these new fields `team` and `heroes` are not declared with `Relationship()`, because `HeroPublicWithTeam` and `TeamPublicWithHeroes` are not **table models**, they cannot have **relationship attributes** with the magic access to get that data from the database.\n\nInstead, here these are only **data models** that will tell FastAPI **which attributes** to get data from and **which data** to get from them.\n\n### Reference to Other Models\n\nAlso, notice that in the `HeroPublicWithTeam` model, the field `team` is not declared with this new `TeamPublicWithHeroes`, because that would again create that infinite recursion of data. Instead, we declare it with the normal `TeamPublic` model.\n\nAnd the same for `TeamPublicWithHeroes`, the model used for the new field `heroes` uses `HeroPublic` to get only each hero's data.\n\nThis also means that, even though we have these two new models, **we still need the previous ones**, `HeroPublic` and `TeamPublic`, because we need to reference them here (and we are also using them in the rest of the *path operations*).\n\n## Update the Path Operations\n\nNow we can update the *path operations* to use the new models.\n\nThis will tell **FastAPI** to take the object that we return from the *path operation function* (a **table model**) and **access the additional attributes** from them to extract their data.\n\nIn the case of the hero, this tells FastAPI to extract the `team` too. And in the case of the team, to extract the list of `heroes` too.\n\n{* ./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py ln[111:116,164:169] hl[111,116,164,169] *}\n\n## Check It Out in the Docs UI\n\nNow let's try it out again in the **docs UI**.\n\nLet's try again with the same **hero** with ID `1`:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI getting a single hero with team\" src=\"/img/tutorial/fastapi/relationships/image03.png\">\n\nNow we get the **team** data included:\n\n```JSON hl_lines=\"7-11\"\n{\n    \"name\": \"Deadpond\",\n    \"secret_name\": \"Dive Wilson\",\n    \"age\": null,\n    \"team_id\": 1,\n    \"id\": 1,\n    \"team\": {\n        \"name\": \"Z-Force\",\n        \"headquarters\": \"Sister Margaret's Bar\",\n        \"id\": 1\n    }\n}\n```\n\nAnd if we get now the **team** with ID `2`:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI getting a single team with the list of heroes\" src=\"/img/tutorial/fastapi/relationships/image04.png\">\n\nNow we get the list of **heroes** included:\n\n```JSON hl_lines=\"5-41\"\n{\n    \"name\": \"Preventers\",\n    \"headquarters\": \"Sharp Tower\",\n    \"id\": 2,\n    \"heroes\": [\n        {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n            \"team_id\": 2,\n            \"id\": 2\n        },\n        {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": null,\n            \"team_id\": 2,\n            \"id\": 3\n        },\n        {\n            \"name\": \"Tarantula\",\n            \"secret_name\": \"Natalia Roman-on\",\n            \"age\": 32,\n            \"team_id\": 2,\n            \"id\": 6\n        },\n        {\n            \"name\": \"Dr. Weird\",\n            \"secret_name\": \"Steve Weird\",\n            \"age\": 36,\n            \"team_id\": 2,\n            \"id\": 7\n        },\n        {\n            \"name\": \"Captain North America\",\n            \"secret_name\": \"Esteban Rogelios\",\n            \"age\": 93,\n            \"team_id\": 2,\n            \"id\": 8\n        }\n    ]\n}\n```\n\n## Recap\n\nUsing the same techniques to declare additional **data models**, we can tell FastAPI what data to return in the responses, even when we return **table models**.\n\nHere we almost **didn't have to change the FastAPI app** code, but of course, there will be cases where you need to get the data and process it in different ways in the *path operation function* before returning it.\n\nBut even in those cases, you will be able to define the **data models** to use in `response_model` to tell FastAPI how to validate and filter the data.\n\nBy this point, you already have a very robust API to handle data in a SQL database combining **SQLModel** with **FastAPI**, and implementing **best practices**, like data validation, conversion, filtering, and documentation. ✨\n\nIn the next chapter, I'll tell you how to implement automated **testing** for your application using FastAPI and SQLModel. ✅\n"
  },
  {
    "path": "docs/tutorial/fastapi/response-model.md",
    "content": "# FastAPI Response Model with SQLModel\n\nNow I'll show you how to use FastAPI's `response_model` with **SQLModel**.\n\n## Interactive API Docs\n\nUp to now, with the code we have used, the API docs know the data the clients have to send:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/simple-hero-api/image01.png\">\n\nThis interactive docs UI is powered by <a href=\"https://github.com/swagger-api/swagger-ui\" class=\"external-link\" target=\"_blank\">Swagger UI</a>, and what Swagger UI does is to read a big JSON content that defines the API with all the data schemas (data shapes) using the standard <a href=\"https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md\" class=\"external-link\" target=\"_blank\">OpenAPI</a>, and showing it in that nice <abbr title=\"User Interface\">UI</abbr>.\n\nFastAPI automatically **generates that OpenAPI** for Swagger UI to read it.\n\nAnd it generates it **based on the code you write**, using the Pydantic models (in this case **SQLModel** models) and type annotations to know the schemas of the data that the API handles.\n\n## Response Data\n\nBut up to now, the API docs UI doesn't know the schema of the *responses* our app sends back.\n\nYou can see that there's a possible \"Successful Response\" with a code `200`, but we have no idea how the response data would look like.\n\n<img class=\"shadow\" alt=\"API docs UI without response data schemas\" src=\"/img/tutorial/fastapi/response-model/image01.png\">\n\nRight now, we only tell FastAPI the data we want to receive, but we don't tell it yet the data we want to send back.\n\nLet's do that now. 🤓\n\n## Use `response_model`\n\nWe can use `response_model` to tell FastAPI the schema of the data we want to send back.\n\nFor example, we can pass the same `Hero` **SQLModel** class (because it is also a Pydantic model):\n\n{* ./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py ln[31:37] hl[31] *}\n\n## List of Heroes in `response_model`\n\nWe can also use other type annotations, the same way we can use with Pydantic fields. For example, we can pass a list of `Hero`s.\n\nTo do so, we declare the `response_model` with `list[Hero]`:\n\n{* ./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py ln[40:44] hl[40] *}\n\n## FastAPI and Response Model\n\nFastAPI will do data validation and filtering of the response with this `response_model`.\n\nSo this works like a contract between our application and the client.\n\nYou can read more about it in the <a href=\"https://fastapi.tiangolo.com/tutorial/response-model/\" class=\"external-link\" target=\"_blank\">FastAPI docs about `response_model`</a>.\n\n## New API Docs UI\n\nNow we can go back to the docs UI and see that they now show the schema of the response we will receive.\n\n<img class=\"shadow\" alt=\"API docs UI without response data schemas\" src=\"/img/tutorial/fastapi/response-model/image02.png\">\n\nThe clients will know what data they should expect.\n\n## Automatic Clients\n\nThe most visible advantage of using the `response_model` is that it shows up in the API docs UI.\n\nBut there are other advantages, like that FastAPI will do automatic <a href=\"https://fastapi.tiangolo.com/tutorial/response-model/\" class=\"external-link\" target=\"_blank\">data validation and filtering</a> of the response data using this model.\n\nAdditionally, because the schemas are defined in using a standard, there are many tools that can take advantage of this.\n\nFor example, client generators, that can automatically create the code necessary to talk to your API in many languages.\n\n/// info\n\nIf you are curious about the standards, FastAPI generates OpenAPI, that internally uses JSON Schema.\n\nYou can read about all that in the <a href=\"https://fastapi.tiangolo.com/tutorial/first-steps/#openapi\" class=\"external-link\" target=\"_blank\">FastAPI docs - First Steps</a>.\n\n///\n\n## Recap\n\nUse the `response_model` to tell FastAPI the schema of the data you want to send back and have awesome data APIs. 😎\n"
  },
  {
    "path": "docs/tutorial/fastapi/session-with-dependency.md",
    "content": "# Session with FastAPI Dependency\n\nBefore we keep adding things, let's change a bit how we get the session for each request to simplify our life later.\n\n## Current Sessions\n\nUp to now, we have been creating a session in each *path operation*, in a `with` block.\n\n{* ./docs_src/tutorial/fastapi/delete/tutorial001_py310.py ln[48:55] hl[50] *}\n\nThat's perfectly fine, but in many use cases we would want to use <a href=\"https://fastapi.tiangolo.com/tutorial/dependencies/\" class=\"external-link\" target=\"_blank\">FastAPI Dependencies</a>, for example to **verify** that the client is **logged in** and get the **current user** before executing any other code in the *path operation*.\n\nThese dependencies are also very useful during **testing**, because we can **easily replace them**, and then, for example, use a new database for our tests, or put some data before the tests, etc.\n\nSo, let's refactor these sessions to use **FastAPI Dependencies**.\n\n## Create a **FastAPI** Dependency\n\nA **FastAPI** dependency is very simple, it's just a function that returns a value.\n\nIt could use `yield` instead of `return`, and in that case **FastAPI** will make sure it executes all the code **after** the `yield`, once it is done with the request.\n\n{* ./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py ln[40:42] hl[40:42] *}\n\n## Use the Dependency\n\nNow let's make FastAPI execute a dependency and get its value in the *path operation*.\n\nWe import `Depends()` from `fastapi`. Then we use it in the *path operation function* in a **parameter**, the same way we declared parameters to get JSON bodies, path parameters, etc.\n\n{* ./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py ln[1:2,40:42,53:59] hl[1,54] *}\n\n/// tip\n\nHere's a tip about that `*,` thing in the parameters.\n\nHere we are passing the parameter `session` that has a \"default value\" of `Depends(get_session)` before the parameter `hero`, that doesn't have any default value.\n\nPython would normally complain about that, but we can use the initial \"parameter\" `*,` to mark all the rest of the parameters as \"keyword only\", which solves the problem.\n\nYou can read more about it in the FastAPI documentation <a href=\"https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#order-the-parameters-as-you-need-tricks\" class=\"external-link\" target=\"_blank\">Path Parameters and Numeric Validations - Order the parameters as you need, tricks</a>\n\n///\n\nThe value of a dependency will **only be used for one request**, FastAPI will call it right before calling your code and will give you the value from that dependency.\n\nIf it had `yield`, then it will continue the rest of the execution once you are done sending the response. In the case of the **session**, it will finish the cleanup code from the `with` block, closing the session, etc.\n\nThen FastAPI will call it again for the **next request**.\n\nBecause it is called **once per request**, we will still get a **single session per request** as we should, so we are still fine with that. ✅\n\nAnd because dependencies can use `yield`, FastAPI will make sure to run the code **after** the `yield` once it is done, including all the **cleanup code** at the end of the `with` block. So we are also fine with that. ✅\n\n## The `with` Block\n\nThis means that in the main code of the *path operation function*, it will work equivalently to the previous version with the explicit `with` block.\n\n{* ./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py ln[1:2,40:42,53:59] hl[55:59] *}\n\nIn fact, you could think that all that block of code inside of the `create_hero()` function is still inside a `with` block for the **session**, because this is more or less what's happening behind the scenes.\n\nBut now, the `with` block is not explicitly in the function, but in the dependency above:\n\n{* ./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py ln[1:2,40:42,53:59] hl[41:42] *}\n\nWe will see how this is very useful when testing the code later. ✅\n\n## Update the Path Operations to Use the Dependency\n\nNow we can update the rest of the *path operations* to use the new dependency.\n\nWe just declare the dependency in the parameters of the function, with:\n\n```Python\nsession: Session = Depends(get_session)\n```\n\nAnd then we remove the previous `with` block with the old **session**.\n\n{* ./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py ln[1:2,40:42,53:104] hl[54,65,74,83,98] *}\n\n## Recap\n\nYou just learned how to use **FastAPI dependencies** to handle the database session. This will come in handy later when testing the code.\n\nAnd you will see how much these dependencies can help the more you work with FastAPI, to handle **permissions**, **authentication**, resources like database **sessions**, etc. 🚀\n\nIf you want to learn more about dependencies, checkout the <a href=\"https://fastapi.tiangolo.com/tutorial/dependencies/\" class=\"external-link\" target=\"_blank\">FastAPI docs about Dependencies</a>.\n"
  },
  {
    "path": "docs/tutorial/fastapi/simple-hero-api.md",
    "content": "# Simple Hero API with FastAPI\n\nLet's start by building a simple hero web API with **FastAPI**. ✨\n\n## Install **FastAPI**\n\nThe first step is to install FastAPI.\n\nFastAPI is the framework to create the **web API**.\n\nMake sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install them, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install fastapi \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\n## **SQLModel** Code - Models, Engine\n\nNow let's start with the SQLModel code.\n\nWe will start with the **simplest version**, with just heroes (no teams yet).\n\nThis is almost the same code we have seen up to now in previous examples:\n\n{* ./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py ln[2,5:20] hl[19:20] *}\n\nThere's only one change here from the code we have used before, the `check_same_thread` in the `connect_args`.\n\nThat is a configuration that SQLAlchemy passes to the low-level library in charge of communicating with the database.\n\n`check_same_thread` is by default set to `True`, to prevent misuses in some simple cases.\n\nBut here we will make sure we don't share the same **session** in more than one request, and that's the actual **safest way** to prevent any of the problems that configuration is there for.\n\nAnd we also need to disable it because in **FastAPI** each request could be handled by multiple interacting threads.\n\n/// info\n\nThat's enough information for now, you can read more about it in the <a href=\"https://fastapi.tiangolo.com/async/\" class=\"external-link\" target=\"_blank\">FastAPI docs for `async` and `await`</a>.\n\nThe main point is, by ensuring you **don't share** the same **session** with more than one request, the code is already safe.\n\n///\n\n## **FastAPI** App\n\nThe next step is to create the **FastAPI** app.\n\nWe will import the `FastAPI` class from `fastapi`.\n\nAnd then create an `app` object that is an instance of that `FastAPI` class:\n\n{* ./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py ln[1:2,23] hl[1,23] *}\n\n## Create Database and Tables on `startup`\n\nWe want to make sure that once the app starts running, the function `create_db_and_tables` is called. To create the database and tables.\n\nThis should be called only once at startup, not before every request, so we put it in the function to handle the `\"startup\"` event:\n\n{* ./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py ln[23:28] hl[26:28] *}\n\n## Create Heroes *Path Operation*\n\n/// info\n\nIf you need a refresher on what a **Path Operation** is (an endpoint with a specific HTTP Operation) and how to work with it in FastAPI, check out the <a href=\"https://fastapi.tiangolo.com/tutorial/first-steps/\" class=\"external-link\" target=\"_blank\">FastAPI First Steps docs</a>.\n\n///\n\nLet's create the **path operation** code to create a new hero.\n\nIt will be called when a user sends a request with a `POST` **operation** to the `/heroes/` **path**:\n\n{* ./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py ln[23:37] hl[31:32] *}\n\n/// info\n\nIf you need a refresher on some of those concepts, checkout the FastAPI documentation:\n\n* <a href=\"https://fastapi.tiangolo.com/tutorial/first-steps/\" class=\"external-link\" target=\"_blank\">First Steps</a>\n* <a href=\"https://fastapi.tiangolo.com/tutorial/path-params/\" class=\"external-link\" target=\"_blank\">Path Parameters - Data Validation and Data Conversion</a>\n* <a href=\"https://fastapi.tiangolo.com/tutorial/body/\" class=\"external-link\" target=\"_blank\">Request Body</a>\n\n///\n\n## The **SQLModel** Advantage\n\nHere's where having our **SQLModel** class models be both **SQLAlchemy** models and **Pydantic** models at the same time shine. ✨\n\nHere we use the **same** class model to define the **request body** that will be received by our API.\n\nBecause **FastAPI** is based on Pydantic, it will use the same model (the Pydantic part) to do automatic data validation and <abbr title=\"also called serialization, marshalling\">conversion</abbr> from the JSON request to an object that is an actual instance of the `Hero` class.\n\nAnd then, because this same **SQLModel** object is not only a **Pydantic** model instance but also a **SQLAlchemy** model instance, we can use it directly in a **session** to create the row in the database.\n\nSo we can use intuitive standard Python **type annotations**, and we don't have to duplicate a lot of the code for the database models and the API data models. 🎉\n\n/// tip\n\nWe will improve this further later, but for now, it already shows the power of having **SQLModel** classes be both **SQLAlchemy** models and **Pydantic** models at the same time.\n\n///\n\n## Read Heroes *Path Operation*\n\nNow let's add another **path operation** to read all the heroes:\n\n{* ./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py ln[23:44] hl[40:44] *}\n\nThis is pretty straightforward.\n\nWhen a client sends a request to the **path** `/heroes/` with a `GET` HTTP **operation**, we run this function that gets the heroes from the database and returns them.\n\n## One Session per Request\n\nRemember that we should use a SQLModel **session** per each group of operations and if we need other unrelated operations we should use a different session?\n\nHere it is much more obvious.\n\nWe should normally have **one session per request** in most of the cases.\n\nIn some isolated cases, we would want to have new sessions inside, so, **more than one session** per request.\n\nBut we would **never want to *share* the same session** among different requests.\n\nIn this simple example, we just create the new sessions manually in the **path operation functions**.\n\nIn future examples later we will use a <a href=\"https://fastapi.tiangolo.com/tutorial/dependencies/\" class=\"external-link\" target=\"_blank\">FastAPI Dependency</a> to get the **session**, being able to share it with other dependencies and being able to replace it during testing. 🤓\n\n## Run the **FastAPI** Server in Development Mode\n\nNow we are ready to run the FastAPI application.\n\nPut all that code in a file called `main.py`.\n\nThen run it with the `fastapi` <abbr title=\"Command Line Interface\">CLI</abbr>, in development mode:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// info\n\nThe `fastapi` command uses <a href=\"https://www.uvicorn.org/\" class=\"external-link\" target=\"_blank\">Uvicorn</a> underneath.\n\n///\n\nWhen you use `fastapi dev` it starts Uvicorn with the option to reload automatically every time you make a change to the code, this way you will be able to develop faster. 🤓\n\n## Run the **FastAPI** Server in Production Mode\n\nThe development mode should not be used in production, as it includes automatic reload by default it consumes much more resources than necessary, and it would be more error prone, etc.\n\nFor production, use `fastapi run` instead of `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Check the API docs UI\n\nNow you can go to that URL in your browser `http://127.0.0.1:8000`. We didn't create a *path operation* for the root path `/`, so that URL alone will only show a \"Not Found\" error... that \"Not Found\" error is produced by your FastAPI application.\n\nBut you can go to the **automatically generated interactive API documentation** at the path `/docs`: <a href=\"http://127.0.0.1:8000/docs\" class=\"external-link\" target=\"_blank\">http://127.0.0.1:8000/docs</a>. ✨\n\nYou will see that this **automatic API docs <abbr title=\"user interface\">UI</abbr>** has the *paths* that we defined above with their *operations*, and that it already knows the shape of the data that the **path operations** will receive:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/simple-hero-api/image01.png\">\n\n## Play with the API\n\nYou can actually click the button <kbd>Try it out</kbd> and send some requests to create some heroes with the **Create Hero** *path operation*.\n\nAnd then you can get them back with the **Read Heroes** *path operation*:\n\n<img class=\"shadow\" alt=\"Interactive API docs UI reading heroes\" src=\"/img/tutorial/fastapi/simple-hero-api/image02.png\">\n\n## Check the Database\n\nNow you can terminate that server program by going back to the terminal and pressing <kbd>Ctrl+C</kbd>.\n\nAnd then, you can open **DB Browser for SQLite** and check the database, to explore the data and confirm that it indeed saved the heroes. 🎉\n\n<img class=\"shadow\" alt=\"DB Browser for SQLite showing the heroes\" src=\"/img/tutorial/fastapi/simple-hero-api/db-browser-01.png\">\n\n## Recap\n\nGood job! This is already a FastAPI **web API** application to interact with the heroes database. 🎉\n\nThere are several things we can improve and extend. For example, we want the database to decide the ID of each new hero, we don't want to allow a user to send it.\n\nWe will make all those improvements in the next chapters. 🚀\n"
  },
  {
    "path": "docs/tutorial/fastapi/teams.md",
    "content": "# FastAPI Path Operations for Teams - Other Models\n\nLet's now update the **FastAPI** application to handle data for teams.\n\nThis is very similar to the things we have done for heroes, so we will go over it quickly here.\n\nWe will use the same models we used in previous examples, with the **relationship attributes**, etc.\n\n## Add Teams Models\n\nLet's add the models for the teams.\n\nIt's the same process we did for heroes, with a base model, a **table model**, and some other **data models**.\n\nWe have a `TeamBase` **data model**, and from it, we inherit with a `Team` **table model**.\n\nThen we also inherit from the `TeamBase` for the `TeamCreate` and `TeamPublic` **data models**.\n\nAnd we also create a `TeamUpdate` **data model**.\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[1:26] hl[5:7,10:13,16:17,20:21,24:26] *}\n\nWe now also have **relationship attributes**. 🎉\n\nLet's now update the `Hero` models too.\n\n## Update Hero Models\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[29:55] hl[29:34,37:40,43:44,47:48,51:55] *}\n\nWe now have a `team_id` in the hero models.\n\nNotice that we can declare the `team_id` in the `HeroBase` because it can be reused by all the models, in all the cases it's an optional integer.\n\nAnd even though the `HeroBase` is *not* a **table model**, we can declare `team_id` in it with the `foreign key` parameter. It won't do anything in most of the models that inherit from `HeroBase`, but in the **table model** `Hero` it will be used to tell **SQLModel** that this is a **foreign key** to that table.\n\n## Relationship Attributes\n\nNotice that the **relationship attributes**, the ones with `Relationship()`, are **only** in the **table models**, as those are the ones that are handled by **SQLModel** with SQLAlchemy and that can have the automatic fetching of data from the database when we access them.\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[5:55] hl[13,40] *}\n\n## Path Operations for Teams\n\nLet's now add the **path operations** for teams.\n\nThese are equivalent and very similar to the **path operations** for the **heroes** we had before, so we don't have to go over the details for each one, let's check the code.\n\n{* ./docs_src/tutorial/fastapi/teams/tutorial001_py310.py ln[135:188] hl[135:141,144:152,155:160,163:178,181:188] *}\n\n## Using Relationships Attributes\n\nUp to this point, we are actually not using the **relationship attributes**, but we could access them in our code.\n\nIn the next chapter, we will play more with them.\n\n## Check the Docs UI\n\nNow we can check the automatic docs UI to see all the **path operations** for heroes and teams.\n\n<img class=\"shadow\" alt=\"Interactive API docs UI\" src=\"/img/tutorial/fastapi/teams/image01.png\">\n\n## Recap\n\nWe can use the same patterns to add more models and API **path operations** to our **FastAPI** application. 🎉\n"
  },
  {
    "path": "docs/tutorial/fastapi/tests.md",
    "content": "# Test Applications with FastAPI and SQLModel\n\nTo finish this group of chapters about **FastAPI** with **SQLModel**, let's now learn how to implement automated tests for an application using FastAPI with SQLModel. ✅\n\nIncluding the tips and tricks. 🎁\n\n## FastAPI Application\n\nLet's work with one of the **simpler** FastAPI applications we built in the previous chapters.\n\nAll the same **concepts**, **tips** and **tricks** will apply to more complex applications as well.\n\nWe will use the application with the hero models, but without team models, and we will use the dependency to get a **session**.\n\nNow we will see how useful it is to have this session dependency. ✨\n\n{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/main.py ln[0] *}\n\n## File Structure\n\nNow we will have a Python project with multiple files, one file `main.py` with all the application, and one file `test_main.py` with the tests, with the same ideas from [Code Structure and Multiple Files](../code-structure.md){.internal-link target=_blank}.\n\nThe file structure is:\n\n```\n.\n├── project\n    ├── __init__.py\n    ├── main.py\n    └── test_main.py\n```\n\n## Testing FastAPI Applications\n\nIf you haven't done testing in FastAPI applications, first check the <a href=\"https://fastapi.tiangolo.com/tutorial/testing/\" class=\"external-link\" target=\"_blank\">FastAPI docs about Testing</a>.\n\nThen, we can continue here, the first step is to install the dependencies, `requests` and `pytest`.\n\nMake sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install them, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install requests pytest\n\n---> 100%\n```\n\n</div>\n\n## Basic Tests Code\n\nLet's start with a simple test, with just the basic test code we need the check that the **FastAPI** application is creating a new hero correctly.\n\n```{ .python .annotate }\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:1-7]!}\n        # Some code here omitted, we will see it later 👈\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:20-24]!}\n        # Some code here omitted, we will see it later 👈\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:26-32]!}\n\n# Code below omitted 👇\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_001.md!}\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\nThat's the **core** of the code we need for all the tests later.\n\nBut now, we need to deal with a bit of logistics and details we are not paying attention to just yet. 🤓\n\n## Testing Database\n\nThis test looks fine, but there's a problem.\n\nIf we run it, it will use the same **production database** that we are using to store our very important **heroes**, and we will end up adding unnecessary data to it, or even worse, in future tests we could end up removing production data.\n\nSo, we should use an independent **testing database**, just for the tests.\n\nTo do this, we need to change the URL used for the database.\n\nBut when the code for the API is executed, it gets a **session** that is already connected to an **engine**, and the **engine** is already using a specific database URL.\n\nEven if we import the variable from the `main` module and change its value just for the tests, by that point the **engine** is already created with the original value.\n\nBut all our API *path operations* get the *session* using a FastAPI **dependency**, and we can override dependencies in tests.\n\nHere's where dependencies start to help a lot.\n\n## Override a Dependency\n\nLet's override the `get_session()` dependency for the tests.\n\nThis dependency is used by all the *path operations* to get the **SQLModel** session object.\n\nWe will override it to use a different **session** object just for the tests.\n\nThat way we protect the production database and we have better control of the data we are testing.\n\n```{ .python .annotate hl_lines=\"4  9-10  12  19\" }\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_002.py[ln:1-7]!}\n        # Some code here omitted, we will see it later 👈\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_002.py[ln:15-32]!}\n\n# Code below omitted 👇\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_002.md!}\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\n## Create the Engine and Session for Testing\n\nNow let's create that **session** object that will be used during testing.\n\nIt will use its own **engine**, and this new engine will use a new URL for the testing database:\n\n```\nsqlite:///testing.db\n```\n\nSo, the testing database will be in the file `testing.db`.\n\n``` { .python .annotate hl_lines=\"4  8-11  13  16  33\"}\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_003.py!}\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_003.md!}\n\n### Import Table Models\n\nHere we create all the tables in the testing database with:\n\n```Python\nSQLModel.metadata.create_all(engine)\n```\n\nBut remember that [Order Matters](../create-db-and-table.md#sqlmodel-metadata-order-matters){.internal-link target=_blank} and we need to make sure all the **SQLModel** models are already defined and **imported** before calling `.create_all()`.\n\nIn this case, it all works for a little subtlety that deserves some attention.\n\nBecause we import something, *anything*, from `.main`, the code in `.main` will be executed, including the definition of the **table models**, and that will automatically register them in `SQLModel.metadata`.\n\nThat way, when we call `.create_all()` all the **table models** are correctly registered in `SQLModel.metadata` and it will all work. 👌\n\n## Memory Database\n\nNow we are not using the production database. Instead, we use a **new testing database** with the `testing.db` file, which is great.\n\nBut SQLite also supports having an **in memory** database. This means that all the database is only in memory, and it is never saved in a file on disk.\n\nAfter the program terminates, **the in-memory database is deleted**, so it wouldn't help much for a production database.\n\nBut **it works great for testing**, because it can be quickly created before each test, and quickly removed after each test. ✅\n\nAnd also, because it never has to write anything to a file and it's all just in memory, it will be even faster than normally. 🏎\n\n/// details | Other alternatives and ideas 👀\n\nBefore arriving at the idea of using an **in-memory database** we could have explored other alternatives and ideas.\n\nThe first is that we are not deleting the file after we finish the test, so the next test could have **leftover data**. So, the right thing would be to delete the file right after finishing the test. 🔥\n\nBut if each test has to create a new file and then delete it afterwards, running all the tests could be **a bit slow**.\n\nRight now, we have a file `testing.db` that is used by all the tests (we only have one test now, but we will have more).\n\nSo, if we tried to run the tests at the same time **in parallel** to try to speed things up a bit, they would clash trying to use the *same* `testing.db` file.\n\nOf course, we could also fix that, using some **random name** for each testing database file... but in the case of SQLite, we have an even better alternative by just using an **in-memory database**. ✨\n\n///\n\n## Configure the In-Memory Database\n\nLet's update our code to use the in-memory database.\n\nWe just have to change a couple of parameters in the **engine**.\n\n```{ .python .annotate hl_lines=\"3  9-13\"}\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_004.py[ln:1-13]!}\n\n# Code below omitted 👇\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_004.md!}\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\nThat's it, now the test will run using the **in-memory database**, which will be faster and probably safer.\n\nAnd all the other tests can do the same.\n\n## Boilerplate Code\n\nGreat, that works, and you could replicate all that process in each of the test functions.\n\nBut we had to add a lot of **boilerplate code** to handle the custom database, creating it in memory, the custom session, and the dependency override.\n\nDo we really have to duplicate all that for **each test**? No, we can do better! 😎\n\nWe are using **pytest** to run the tests. And pytest also has a very similar concept to the **dependencies in FastAPI**.\n\n/// info\n\nIn fact, pytest was one of the things that inspired the design of the dependencies in FastAPI.\n\n///\n\nIt's a way for us to declare some **code that should be run before** each test and **provide a value** for the test function (that's pretty much the same as FastAPI dependencies).\n\nIn fact, it also has the same trick of allowing to use `yield` instead of `return` to provide the value, and then **pytest** makes sure that the code after `yield` is executed *after* the function with the test is done.\n\nIn pytest, these things are called **fixtures** instead of *dependencies*.\n\nLet's use these **fixtures** to improve our code and reduce de duplicated boilerplate for the next tests.\n\n## Pytest Fixtures\n\nYou can read more about them in the <a href=\"https://docs.pytest.org/en/6.2.x/fixture.html\" class=\"external-link\" target=\"_blank\">pytest docs for fixtures</a>, but I'll give you a short example for what we need here.\n\nLet's see the first code example with a fixture:\n\n``` { .python .annotate }\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_005.py!}\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_005.md!}\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\n**pytest** fixtures work in a very similar way to FastAPI dependencies, but have some minor differences:\n\n* In pytest fixtures, we need to add a decorator of `@pytest.fixture()` on top.\n* To use a pytest fixture in a function, we have to declare the parameter with the **exact same name**. In FastAPI we have to **explicitly use `Depends()`** with the actual function inside it.\n\nBut apart from the way we declare them and how we tell the framework that we want to have them in the function, they **work in a very similar way**.\n\nNow we create lot's of tests and re-use that same fixture in all of them, saving us that **boilerplate code**.\n\n**pytest** will make sure to run them right before (and finish them right after) each test function. So, each test function will actually have its own database, engine, and session.\n\n## Client Fixture\n\nAwesome, that fixture helps us prevent a lot of duplicated code.\n\nBut currently, we still have to write some code in the test function that will be repetitive for other tests, right now we:\n\n* create the **dependency override**\n* put it in the `app.dependency_overrides`\n* create the `TestClient`\n* Clear the dependency override(s) after making the request\n\nThat's still gonna be repetitive in the other future tests. Can we improve it? Yes! 🎉\n\nEach **pytest** fixture (the same way as **FastAPI** dependencies), can require other fixtures.\n\nSo, we can create a **client fixture** that will be used in all the tests, and it will itself require the **session fixture**.\n\n``` { .python .annotate hl_lines=\"19-28  31\" }\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_006.py!}\n```\n\n{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_006.md!}\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\nNow we have a **client fixture** that, in turn, uses the **session fixture**.\n\nAnd in the actual test function, we just have to declare that we require this **client fixture**.\n\n## Add More Tests\n\nAt this point, it all might seem like we just did a lot of changes for nothing, to get **the same result**. 🤔\n\nBut normally we will create **lots of other test functions**. And now all the boilerplate and complexity is **written only once**, in those two fixtures.\n\nLet's add some more tests:\n\n{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[30:58] hl[30,49] *}\n\n/// tip\n\nIt's always **good idea** to not only test the normal case, but also that **invalid data**, **errors**, and **corner cases** are handled correctly.\n\nThat's why we add these two extra tests here.\n\n///\n\nNow, any additional test functions can be as **simple** as the first one, they just have to **declare the `client` parameter** to get the `TestClient` **fixture** with all the database stuff setup. Nice! 😎\n\n## Why Two Fixtures\n\nNow, seeing the code, we could think, why do we put **two fixtures** instead of **just one** with all the code? And that makes total sense!\n\nFor these examples, **that would have been simpler**, there's no need to separate that code into two fixtures for them...\n\nBut for the next test function, we will require **both fixtures**, the **client** and the **session**.\n\n{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[1:6,61:81] hl[6,61] *}\n\nIn this test function, we want to check that the *path operation* to **read a list of heroes** actually sends us heroes.\n\nBut if the **database is empty**, we would get an **empty list**, and we wouldn't know if the hero data is being sent correctly or not.\n\nBut we can **create some heroes** in the testing database right before sending the API request. ✨\n\nAnd because we are using the **testing database**, we don't affect anything by creating heroes for the test.\n\nTo do it, we have to:\n\n* import the `Hero` model\n* require both fixtures, the **client** and the **session**\n* create some heroes and save them in the database using the **session**\n\nAfter that, we can send the request and check that we actually got the data back correctly from the database. 💯\n\nHere's the important detail to notice: we can require fixtures in other fixtures **and also** in the test functions.\n\nThe function for the **client fixture** and the actual testing function will **both** receive the same **session**.\n\n## Add the Rest of the Tests\n\nUsing the same ideas, requiring the fixtures, creating data that we need for the tests, etc., we can now add the rest of the tests. They look quite similar to what we have done up to now.\n\n{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[84:125] hl[84,99,114] *}\n\n## Run the Tests\n\nNow we can run the tests with `pytest` and see the results:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n============= test session starts ==============\nplatform linux -- Python 3.10.0, pytest-7.4.4, pluggy-1.5.0\nrootdir: /home/user/code/sqlmodel-tutorial\n<b>collected 7 items                              </b>\n\n---> 100%\n\nproject/test_main.py <font color=\"#A6E22E\">.......         [100%]</font>\n\n<font color=\"#A6E22E\">============== </font><font color=\"#A6E22E\"><b>7 passed</b></font><font color=\"#A6E22E\"> in 0.83s ===============</font>\n```\n\n</div>\n\n## Recap\n\nDid you read all that? Wow, I'm impressed! 😎\n\nAdding tests to your application will give you a lot of **certainty** that everything is **working correctly**, as you intended.\n\nAnd tests will be notoriously useful when **refactoring** your code, **changing things**, **adding features**. Because tests can help catch a lot of errors that can be easily introduced by refactoring.\n\nAnd they will give you the confidence to work faster and **more efficiently**, because you know that you are checking if you are **not breaking anything**. 😅\n\nI think tests are one of those things that bring your code and you as a developer to the next professional level. 😎\n\nAnd if you read and studied all this, you already know a lot of the advanced ideas and tricks that took me years to learn. 🚀\n"
  },
  {
    "path": "docs/tutorial/fastapi/update-extra-data.md",
    "content": "# Update with Extra Data (Hashed Passwords) with FastAPI\n\nIn the previous chapter I explained to you how to update data in the database from input data coming from a **FastAPI** *path operation*.\n\nNow I'll explain to you how to add **extra data**, additional to the input data, when updating or creating a model object.\n\nThis is particularly useful when you need to **generate some data** in your code that is **not coming from the client**, but you need to store it in the database. For example, to store a **hashed password**.\n\n## Password Hashing\n\nLet's imagine that each hero in our system also has a **password**.\n\nWe should never store the password in plain text in the database, we should only stored a **hashed version** of it.\n\n\"**Hashing**\" means converting some content (a password in this case) into a sequence of bytes (just a string) that looks like gibberish.\n\nWhenever you pass exactly the same content (exactly the same password) you get exactly the same gibberish.\n\nBut you **cannot convert** from the gibberish **back to the password**.\n\n### Why use Password Hashing\n\nIf your database is stolen, the thief won't have your users' **plaintext passwords**, only the hashes.\n\nSo, the thief won't be able to try to use that password in another system (as many users use the same password everywhere, this would be dangerous).\n\n/// tip\n\nYou could use <a href=\"https://passlib.readthedocs.io/en/stable/\" class=\"external-link\" target=\"_blank\">passlib</a> to hash passwords.\n\nIn this example we will use a fake hashing function to focus on the data changes. 🤡\n\n///\n\n## Update Models with Extra Data\n\nThe `Hero` table model will now store a new field `hashed_password`.\n\nAnd the data models for `HeroCreate` and `HeroUpdate` will also have a new field `password` that will contain the plain text password sent by clients.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial002_py310.py ln[5:28] hl[13,17,28] *}\n\nWhen a client is creating a new hero, they will send the `password` in the request body.\n\nAnd when they are updating a hero, they could also send the `password` in the request body to update it.\n\n## Hash the Password\n\nThe app will receive the data from the client using the `HeroCreate` model.\n\nThis contains the `password` field with the plain text password, and we cannot use that one. So we need to generate a hash from it.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial002_py310.py ln[42:44,55:57] hl[57] *}\n\n## Create an Object with Extra Data\n\nNow we need to create the database hero.\n\nIn previous examples, we have used something like:\n\n```Python\ndb_hero = Hero.model_validate(hero)\n```\n\nThis creates a `Hero` (which is a *table model*) object from the `HeroCreate` (which is a *data model*) object that we received in the request.\n\nAnd this is all good... but as `Hero` doesn't have a field `password`, it won't be extracted from the object `HeroCreate` that has it.\n\n`Hero` actually has a `hashed_password`, but we are not providing it. We need a way to provide it...\n\n### Dictionary Update\n\nLet's pause for a second to check this, when working with dictionaries, there's a way to `update` a dictionary with extra data from another dictionary, something like this:\n\n```Python hl_lines=\"14\"\ndb_user_dict = {\n    \"name\": \"Deadpond\",\n    \"secret_name\": \"Dive Wilson\",\n    \"age\": None,\n}\n\nhashed_password = \"fakehashedpassword\"\n\nextra_data = {\n    \"hashed_password\": hashed_password,\n    \"age\": 32,\n}\n\ndb_user_dict.update(extra_data)\n\nprint(db_user_dict)\n\n# {\n#     \"name\": \"Deadpond\",\n#     \"secret_name\": \"Dive Wilson\",\n#     \"age\": 32,\n#     \"hashed_password\": \"fakehashedpassword\",\n# }\n```\n\nThis `update` method allows us to add and override things in the original dictionary with the data from another dictionary.\n\nSo now, `db_user_dict` has the updated `age` field with `32` instead of `None` and more importantly, **it has the new `hashed_password` field**.\n\n### Create a Model Object with Extra Data\n\nSimilar to how dictionaries have an `update` method, **SQLModel** models have a parameter `update` in `Hero.model_validate()` that takes a dictionary with extra data, or data that should take precedence:\n\n{* ./docs_src/tutorial/fastapi/update/tutorial002_py310.py ln[55:64] hl[60] *}\n\nNow, `db_hero` (which is a *table model* `Hero`) will extract its values from `hero` (which is a *data model* `HeroCreate`), and then it will **`update`** its values with the extra data from the dictionary `extra_data`.\n\nIt will only take the fields defined in `Hero`, so **it will not take the `password`** from `HeroCreate`. And it will also **take its values** from the **dictionary passed to the `update`** parameter, in this case, the `hashed_password`.\n\nIf there's a field in both `hero` and the `extra_data`, **the value from the `extra_data` passed to `update` will take precedence**.\n\n## Update with Extra Data\n\nNow let's say we want to **update a hero** that already exists in the database.\n\nThe same way as before, to avoid removing existing data, we will use `exclude_unset=True` when calling `hero.model_dump()`, to get a dictionary with only the data sent by the client.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial002_py310.py ln[83:89] hl[89] *}\n\nNow, this `hero_data` dictionary could contain a `password`. We need to check it, and if it's there, we need to generate the `hashed_password`.\n\nThen we can put that `hashed_password` in a dictionary.\n\nAnd then we can update the `db_hero` object using the method `db_hero.sqlmodel_update()`.\n\nIt takes a model object or dictionary with the data to update the object and also an **additional `update` argument** with extra data.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial002_py310.py ln[83:99] hl[95] *}\n\n/// tip\n\nThe method `db_hero.sqlmodel_update()` was added in SQLModel 0.0.16. 😎\n\n///\n\n## Recap\n\nYou can use the `update` parameter in `Hero.model_validate()` to provide extra data when creating a new object and `Hero.sqlmodel_update()` to provide extra data when updating an existing object. 🤓\n"
  },
  {
    "path": "docs/tutorial/fastapi/update.md",
    "content": "# Update Data with FastAPI\n\nNow let's see how to update data in the database with a **FastAPI** *path operation*.\n\n## `HeroUpdate` Model\n\nWe want clients to be able to update the `name`, the `secret_name`, and the `age` of a hero.\n\nBut we don't want them to have to include all the data again just to **update a single field**.\n\nSo, we need to make all those fields **optional**.\n\nAnd because the `HeroBase` has some of them *required* (without a default value), we will need to **create a new model**.\n\n/// tip\n\nHere is one of those cases where it probably makes sense to use an **independent model** instead of trying to come up with a complex tree of models inheriting from each other.\n\nBecause each field is **actually different** (we just set a default value of `None`, but that's already making it different), it makes sense to have them in their own model.\n\n///\n\nSo, let's create this new `HeroUpdate` model:\n\n{* ./docs_src/tutorial/fastapi/update/tutorial001_py310.py ln[5:26] hl[23:26] *}\n\nThis is almost the same as `HeroBase`, but all the fields are optional, so we can't simply inherit from `HeroBase`.\n\n## Create the Update Path Operation\n\nNow let's use this model in the *path operation* to update a hero.\n\nWe will use a `PATCH` HTTP operation. This is used to **partially update data**, which is what we are doing.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial001_py310.py ln[74:89] hl[74:75] *}\n\nWe also read the `hero_id` from the *path parameter* and the request body, a `HeroUpdate`.\n\n### Read the Existing Hero\n\nWe take a `hero_id` with the **ID** of the hero **we want to update**.\n\nSo, we need to read the hero from the database, with the **same logic** we used to **read a single hero**, checking if it exists, possibly raising an error for the client if it doesn't exist, etc.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial001_py310.py ln[74:89] hl[77:79] *}\n\n### Get the New Data\n\nThe `HeroUpdate` model has all the fields with **default values**, because they all have defaults, they are all optional, which is what we want.\n\nBut that also means that if we just call `hero.model_dump()` we will get a dictionary that could potentially have several or all of those values with their defaults, for example:\n\n```Python\n{\n    \"name\": None,\n    \"secret_name\": None,\n    \"age\": None,\n}\n```\n\nAnd then, if we update the hero in the database with this data, we would be removing any existing values, and that's probably **not what the client intended**.\n\nBut fortunately Pydantic models (and so SQLModel models) have a parameter we can pass to the `.model_dump()` method for that: `exclude_unset=True`.\n\nThis tells Pydantic to **not include** the values that were **not sent** by the client. Saying it another way, it would **only** include the values that were **sent by the client**.\n\nSo, if the client sent a JSON with no values:\n\n```JSON\n{}\n```\n\nThen the dictionary we would get in Python using `hero.model_dump(exclude_unset=True)` would be:\n\n```Python\n{}\n```\n\nBut if the client sent a JSON with:\n\n```JSON\n{\n    \"name\": \"Deadpuddle\"\n}\n```\n\nThen the dictionary we would get in Python using `hero.model_dump(exclude_unset=True)` would be:\n\n```Python\n{\n    \"name\": \"Deadpuddle\"\n}\n```\n\nThen we use that to get the data that was actually sent by the client:\n\n{* ./docs_src/tutorial/fastapi/update/tutorial001_py310.py ln[74:89] hl[80] *}\n\n/// tip\nBefore SQLModel 0.0.14, the method was called `hero.dict(exclude_unset=True)`, but it was renamed to `hero.model_dump(exclude_unset=True)` to be consistent with Pydantic v2.\n///\n\n## Update the Hero in the Database\n\nNow that we have a **dictionary with the data sent by the client**, we can use the method `db_hero.sqlmodel_update()` to update the object `db_hero`.\n\n{* ./docs_src/tutorial/fastapi/update/tutorial001_py310.py ln[74:89] hl[81] *}\n\n/// tip\n\nThe method `db_hero.sqlmodel_update()` was added in SQLModel 0.0.16. 🤓\n\nBefore that, you would need to manually get the values and set them using `setattr()`.\n\n///\n\nThe method `db_hero.sqlmodel_update()` takes an argument with another model object or a dictionary.\n\nFor each of the fields in the **original** model object (`db_hero` in this example), it checks if the field is available in the **argument** (`hero_data` in this example) and then updates it with the provided value.\n\n## Remove Fields\n\nHere's a bonus. 🎁\n\nWhen getting the dictionary of data sent by the client, we only include **what the client actually sent**.\n\nThis sounds simple, but it has some additional nuances that become **nice features**. ✨\n\nWe are **not simply omitting** the data that has the **default values**.\n\nAnd we are **not simply omitting** anything that is `None`.\n\nThis means that if a model in the database **has a value different than the default**, the client could **reset it to the same value as the default**, or even `None`, and we would **still notice it** and **update it accordingly**. 🤯🚀\n\nSo, if the client wanted to intentionally remove the `age` of a hero, they could just send a JSON with:\n\n```JSON\n{\n    \"age\": null\n}\n```\n\nAnd when getting the data with `hero.model_dump(exclude_unset=True)`, we would get:\n\n```Python\n{\n    \"age\": None\n}\n```\n\nSo, we would use that value and update the `age` to `None` in the database, **just as the client intended**.\n\nNotice that `age` here is `None`, and **we still detected it**.\n\nAlso, that `name` was not even sent, and we don't *accidentally* set it to `None` or something. We just didn't touch it because the client didn't send it, so we are **perfectly fine**, even in these corner cases. ✨\n\nThese are some of the advantages of Pydantic, that we can use with SQLModel. 🎉\n\n## Recap\n\nUsing `.model_dump(exclude_unset=True)` in SQLModel models (and Pydantic models) we can easily update data **correctly**, even in the **edge cases**. 😎\n"
  },
  {
    "path": "docs/tutorial/index.md",
    "content": "# Tutorial - User Guide\n\nIn this tutorial you will learn how to use **SQLModel**.\n\n## Type hints\n\nIf you need a refresher about how to use Python type hints (type annotations), check <a href=\"https://fastapi.tiangolo.com/python-types/\" class=\"external-link\" target=\"_blank\">FastAPI's Python types intro</a>.\n\nYou can also check the <a href=\"https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html\" class=\"external-link\" target=\"_blank\">mypy cheat sheet</a>.\n\n**SQLModel** uses type annotations for everything, this way you can use a familiar Python syntax and get all the editor support possible, with autocompletion and in-editor error checking.\n\n## Intro\n\nThis tutorial shows you how to use **SQLModel** with all its features, step by step.\n\nEach section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific needs.\n\nIt is also built to work as a future reference.\n\nSo you can come back and see exactly what you need.\n\n## Run the code\n\nAll the code blocks can be copied and used directly (they are tested Python files).\n\nIt is **HIGHLY encouraged** that you write or copy the code, edit it, and run it locally.\n\nUsing it in your editor is what really shows you the benefits of **SQLModel**, seeing how much code it saves you, and all the editor support you get, with autocompletion and in-editor error checks, preventing lots of bugs.\n\nRunning the examples is what will really help you understand what is going on.\n\nYou can learn a lot more by running some examples and playing around with them than by reading all the docs here.\n"
  },
  {
    "path": "docs/tutorial/indexes.md",
    "content": "# Indexes - Optimize Queries\n\nWe just saw how to get some data `WHERE` a **condition** is true. For example, where the hero **name is \"Deadpond\"**.\n\nIf we just create the tables and the data as we have been doing, when we `SELECT` some data using `WHERE`, the database would have to **scan** through **each one of the records** to find the ones that **match**. This is not a problem with 3 heroes as in these examples.\n\nBut imagine that your database has **thousands** or **millions** of **records**, if every time you want to find the heroes with the name \"Deadpond\" it has to scan through **all** of the records to find all the possible matches, then that becomes problematic, as it would be too slow.\n\nI'll show you how to handle it with a database **index**.\n\nThe change in the code is **extremely small**, but it's useful to understand what's happening behind the scenes, so I'll show you **how it all works** and what it means.\n\n---\n\nIf you already executed the previous examples and have a database with data, **remove the database file** before running each example, that way you won't have duplicate data and you will be able to get the same results.\n\n## No Time to Explain\n\nAre you already a **SQL expert** and don't have time for all my explanations?\n\nFine, in that case, you can **sneak peek** the final code to create indexes here.\n\n{* ./docs_src/tutorial/indexes/tutorial002_py310.py ln[0] *}\n\n..but if you are not an expert, **continue reading**, this will probably be useful. 🤓\n\n## What is an Index\n\nIn general, an **index** is just something we can have to help us **find things faster**. It normally works by having things in **order**. Let's think about some real-life examples before even thinking about databases and code.\n\n### An Index and a Dictionary\n\nImagine a **dictionary**, a book with definitions of words. 📔 ...not a Python `dict`. 😅\n\nLet's say that you want to **find a word**, for example the word \"**database**\". You take the dictionary, and open it somewhere, for example in the middle. Maybe you see some definitions of words that start with `m`, like `manual`, so you conclude that you are in the letter `m` in the dictionary.\n\n<img src=\"/img/tutorial/indexes/dictionary001.drawio.svg\">\n\nYou know that in the alphabet, the letter `d` for `database` comes **before** the letter `m` for `manual`.\n\n<img src=\"/img/tutorial/indexes/dictionary002.drawio.svg\">\n\nSo, you know you have to search in the dictionary **before** the point you currently are. You still don't know where the word `database` is, because you don't know exactly where the letter `d` is in the dictionary, but you know that **it is not after** that point, you can now **discard the right half** of the dictionary in your search.\n\n<img src=\"/img/tutorial/indexes/dictionary003.drawio.svg\">\n\nNext, you **open the dictionary again**, but only taking into account the **half of the dictionary** that can contain the word you want, the **left part of the dictionary**. You open it in the middle of that left part and now you arrive maybe at the letter `f`.\n\n<img src=\"/img/tutorial/indexes/dictionary004.drawio.svg\">\n\nYou know that `d` from `database` comes before `f`. So it has to be **before** that. But now you know that `database` **is not after** that point, and you can discard the dictionary from that point onward.\n\n<img src=\"/img/tutorial/indexes/dictionary005.drawio.svg\">\n\nNow you have a **small section of dictionary** to search (only a **quarter** of dictionary can have your word). You take that **quarter** of the pages at the start of the dictionary that can contain your word, and open it in the middle of that section. Maybe you arrive at the letter `c`.\n\n<img src=\"/img/tutorial/indexes/dictionary005.drawio.svg\">\n\nYou know the word `database` has to be **after** that and **not before** that point, so you can discard the left part of that block of pages.\n\n<img src=\"/img/tutorial/indexes/dictionary007.drawio.svg\">\n\nYou repeat this process **a few more times**, and you finally arrive at the letter `d`, you continue with the same process in that section for the letter `d` and you finally **find the word** `database`. 🎉\n\n<img src=\"/img/tutorial/indexes/dictionary008.drawio.svg\">\n\nYou had to open the dictionary a few times, maybe **5 or 10**. That's actually **very little work** compared to what it could have been.\n\n/// note  | Technical Details\n\nDo you like **fancy words**? Cool! Programmers tend to like fancy words. 😅\n\nThat <abbr title=\"a recipe, a sequence of predefined steps that achieve a result\">algorithm</abbr> I showed you above is called **Binary Search**.\n\nIt's called that because you **search** something by splitting the dictionary (or any ordered list of things) in **two** (\"binary\" means \"two\") parts. And you do that process multiple times until you find what you want.\n\n///\n\n### An Index and a Novel\n\nLet's now imagine you are reading a **novel book**. And someone told you that at some point, they mention a **database**, and you want to find that chapter.\n\nHow do you find the word \"*database*\" there? You might have to read **the entire book** to find where the word \"*database*\" is located in the book. So, instead of opening the book 5 or 10 times, you would have to open each of the **500 pages** and read them one by one until you find the word. You might enjoy the book, though. 😅\n\nBut if we are only interested in **quickly finding information** (as when working with SQL databases), then reading each of the 500 pages is **too inefficient** when there could be an option to open the book in 5 or 10 places and find what you're looking for.\n\n### A Technical Book with an Index\n\nNow let's imagine you are reading a technical book. For example, with several topics about programming. And there's a couple of sections where it talks about a **database**.\n\nThis book might have a **book index**: a section in the book that has some **names of topics covered** and the **page numbers** in the book where you can read about them. And the topic names are **sorted** in alphabetic order, pretty much like a dictionary (a book with words, as in the previous example).\n\nIn this case, you can open that book in the end (or in the beginning) to find the **book index** section, it would have only a few pages. And then, you can do the same process as with the **dictionary** example above.\n\nOpen the index, and after **5 or 10 steps**, quickly find the topic \"**database**\" with the page numbers where that is covered, for example \"page 253 in Chapter 5\". Now you used the dictionary technique to find the **topic**, and that topic gave you a **page number**.\n\nNow you know that you need to find \"**page 253**\". But by looking at the closed book you still don't know where that page is, so you have to **find that page**. To find it, you can do the same process again, but this time, instead of searching for a **topic** in the **index**, you are searching for a **page number** in the **entire book**. And after **5 or 10 more steps**, you find the page 253 in Chapter 5.\n\n<img src=\"/img/tutorial/indexes/techbook001.drawio.svg\">\n\nAfter this, even though this book is not a dictionary and has some particular content, you were able to **find the section** in the book that talks about a \"**database**\" in a **few steps** (say 10 or 20, instead of reading all the 500 pages).\n\nThe main point is that the index is **sorted**, so we can use the same process we used for the **dictionary** to find the topic. And then that gives us a page number, and the **page numbers are also sorted**! 😅\n\nWhen we have a list of sorted things we can apply the same technique, and that's the whole trick here, we use the same technique first for the **topics** in the index and then for the **page numbers** to find the actual chapter.\n\nSuch efficiency! 😎\n\n## What are Database Indexes\n\n**Database indexes** are very similar to **book indexes**.\n\nDatabase indexes store some info, some keys, in a way that makes it **easy and fast to find** (for example sorted), and then for each key they **point to some data somewhere else** in the database.\n\nLet's see a more clear example. Let's say you have this table in a database:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\nAnd let's imagine you have **many more rows**, many more heroes. Probably **thousands**.\n\nIf you tell the SQL database to get you a hero by a specific name, for example `Spider-Boy` (by using the `name` in the `WHERE` part of the SQL query), the database will have to **scan** all the heroes, checking **one by one** to find all the ones with a name of `Spider-Boy`.\n\nIn this case, there's only one, but there's nothing limiting the database from having **more records with the same name**. And because of that, the database would **continue searching** and checking each one of the records, which would be very slow.\n\nBut now let's say that the database has an index for the column `name`. The index could look something like this, we could imagine that the index is like an additional special table that the database manages automatically:\n\n<table>\n<tr>\n<th>name</th><th>id</th>\n</tr>\n<tr>\n<td>Deadpond</td><td>1</td>\n</tr>\n<tr>\n<td>Rusty-Man</td><td>3</td>\n</tr>\n<tr>\n<td>Spider-Boy</td><td>2</td>\n</tr>\n</table>\n\nIt would have each `name` field from the `hero` table **in order**. It would not be sorted by `id`, but by `name` (in alphabetical order, as the `name` is a string). So, first it would have `Deadpond`, then `Rusty-Man`, and last `Spider-Boy`. It would also include the `id` of each hero. Remember that this could have **thousands** of heroes.\n\nThen the database would be able to use more or less the same ideas in the examples above with the **dictionary** and the **book index**.\n\nIt could start somewhere (for example, in the middle of the index). It could arrive at some hero there in the middle, like `Rusty-Man`. And because the **index** has the `name` fields in order, the database would know that it can **discard all the previous index rows** and **only search** in the following index rows.\n\n<table>\n<tr>\n<th>name</th><th>id</th>\n</tr>\n<tr style=\"background-color: #F5F5F5; color: #999999;\">\n<td>Deadpond</td><td>1</td>\n</tr>\n<tr style=\"background-color: #F5F5F5; color: #999999;\">\n<td>Rusty-Man</td><td>3</td>\n</tr>\n<tr style=\"background-color: #FFF2CC;\">\n<td>Spider-Boy</td><td>2</td>\n</tr>\n</table>\n\nAnd that way, as with the example with the dictionary above, **instead of reading thousands of heroes**, the database would be able to do a few steps, say **5 or 10 steps**, and arrive at the row of the index that has `Spider-Boy`, even if the table (and index) has thousands of rows:\n\n<table>\n<tr>\n<th>name</th><th>id</th>\n</tr>\n<tr style=\"background-color: #F5F5F5; color: #999999;\">\n<td>Deadpond</td><td>1</td>\n</tr>\n<tr style=\"background-color: #F5F5F5; color: #999999;\">\n<td>Rusty-Man</td><td>3</td>\n</tr>\n<tr style=\"background-color: #D5E8D4;\">\n<td>✨ Spider-Boy ✨</td><td>2</td>\n</tr>\n</table>\n\nThen by looking at **this index row**, it would know that the `id` for `Spider-Boy` in the `hero` table is `2`.\n\nSo then it could **search that `id`** in the `hero` table using more or less the **same technique**.\n\nThat way, in the end, instead of reading thousands of records, the database only had to do **a few steps** to find the hero we wanted.\n\n## Updating the Index\n\nAs you can imagine, for all this to work, the index would need to be **up to date** with the data in the database.\n\nIf you had to update it **manually** in code, it would be very cumbersome and **error-prone**, as it would be easy to end up in a state where the index is not up to date and points to incorrect data. 😱\n\nHere's the good news: when you create an index in a **SQL Database**, the database takes care of **updating** it **automatically** whenever it's necessary. 😎🎉\n\nIf you **add new records** to the `hero` table, the database will **automatically** update the index. It will do the **same process** of **finding** the right place to put the new index data (those **5 or 10 steps** described above), and then it will save the new index information there. The same would happen when you **update** or **delete** data.\n\nDefining and creating an index is very **easy** with SQL databases. And then **using it** is even easier... it's transparent. The database will figure out which index to use automatically, the SQL queries don't even change.\n\nSo, in SQL databases **indexes are great**! And are super **easy to use**. Why not just have indexes for everything? .....Because indexes also have a \"**cost**\" in computation and storage (disk space).\n\n## Index Cost\n\nThere's a **cost** associated with **indexes**. 💰\n\nWhen you don't have an index and add a **new row** to the table `hero`, the database has to perform **1 operation** to add the new hero row at the end of the table.\n\nBut if you have an **index** for the **hero names**, now the database has to perform the same **1 operation** to add that row **plus** some extra **5 or 10 operations** in the index, to find the right spot for the name, to then add that **index record** there.\n\nAnd if you have an index for the `name`, one for the `age`, and one for the `secret_name`, now the database has to perform the same **1 operation** to add that row **plus** some extra **5 or 10 operations** in the index **times 3**, for each of the indexes. This means that now adding one row takes something like **31 operations**.\n\nThis also means that you are **exchanging** the time it takes to **read** data for the time it takes to **write** data plus some extra **space** in the database.\n\nIf you have queries that get data out of the database comparing each one of those fields (for example using `WHERE`), then it makes total sense to have indexes for each one of them. Because **31 operations** while creating or updating data (plus the space of the index) is much, much better than the possible **500 or 1000 operations** to read all the rows to be able to compare them using each field.\n\nBut if you **never** have queries that find records by the `secret_name` (you never use `secret_name` in the `WHERE` part) it probably doesn't make sense to have an index for the `secret_name` field/column, as that will increase the computational and space **cost** of writing and updating the database.\n\n## Create an Index with SQL\n\nPhew, that was a lot of theory and explanations. 😅\n\nThe most important thing about indexes is **understanding** them, how, and when to use them.\n\nLet's now see the **SQL** syntax to create an **index**. It is very simple:\n\n```SQL hl_lines=\"3\"\nCREATE INDEX ix_hero_name\nON hero (name)\n```\n\nThis means, more or less:\n\n> Hey SQL database 👋, please `CREATE` an `INDEX` for me.\n>\n> I want the name of the index to be `ix_hero_name`.\n>\n> This index should be `ON` the table `hero`, it refers to that table.\n>\n> The column I want you to use for it is `name`.\n\n## Declare Indexes with SQLModel\n\nAnd now let's see how to define indexes in **SQLModel**.\n\nThe change in code is underwhelming, it's very simple. 😆\n\nHere's the `Hero` model we had before:\n\n{* ./docs_src/tutorial/where/tutorial001_py310.py ln[1:8] hl[6] *}\n\nLet's now update it to tell **SQLModel** to create an index for the `name` field when creating the table:\n\n{* ./docs_src/tutorial/indexes/tutorial001_py310.py ln[1:8] hl[6] *}\n\nWe use the same `Field()` again as we did before, and set `index=True`. That's it! 🚀\n\nNotice that we didn't set an argument of `default=None` or anything similar. This means that **SQLModel** (thanks to Pydantic) will keep it as a **required** field.\n\n/// info\n\nSQLModel (actually SQLAlchemy) will **automatically generate the index name** for you.\n\nIn this case the generated name would be `ix_hero_name`.\n\n///\n\n## Query Data\n\nNow, to query the data using the field `name` and the new index we don't have to do anything special or different in the code, it's just **the same code**.\n\nThe SQL database will figure it out **automatically**. ✨\n\nThis is great because it means that indexes are very **simple to use**. But it might also feel counterintuitive at first, as you are **not doing anything** explicitly in the code to make it obvious that the index is useful, it all happens in the database behind the scenes.\n\n{* ./docs_src/tutorial/indexes/tutorial001_py310.py ln[34:39] hl[36] *}\n\nThis is exactly the same code as we had before, but now the database will **use the index** underneath.\n\n## Run the Program\n\nIf you run the program now, you will see an output like this:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Create the table\nCREATE TABLE hero (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        PRIMARY KEY (id)\n)\n\n// Create the index 🤓🎉\nCREATE INDEX ix_hero_name ON hero (name)\n\n// The SELECT with WHERE looks the same\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00014s] ('Deadpond',)\n\n// The resulting hero\nsecret_name='Dive Wilson' age=None id=1 name='Deadpond'\n```\n\n</div>\n\n## More Indexes\n\nWe are going to query the `hero` table doing comparisons on the `age` field too, so we should **define an index** for that one as well:\n\n{* ./docs_src/tutorial/indexes/tutorial002_py310.py ln[1:8] hl[8] *}\n\nIn this case, we want the default value of `age` to continue being `None`, so we set `default=None` when using `Field()`.\n\nNow when we use **SQLModel** to create the database and tables, it will also create the **indexes** for these two columns in the `hero` table.\n\nSo, when we query the database for the `hero` table and use those **two columns** to define what data we get, the database will be able to **use those indexes** to improve the **reading performance**. 🚀\n\n## Primary Key and Indexes\n\nYou probably noticed that we didn't set `index=True` for the `id` field.\n\nBecause the `id` is already the **primary key**, the database will automatically create an internal **index** for it.\n\nThe database always creates an internal index for **primary keys** automatically, as those are the primary way to organize, store, and retrieve data. 🤓\n\nBut if you want to be **frequently querying** the SQL database for any **other field** (e.g. using any other field in the `WHERE` section), you will probably want to have at least an **index** for that.\n\n## Recap\n\n**Indexes** are very important to improve **reading performance** and speed when querying the database. 🏎\n\nCreating and using them is very **simple** and easy. The most important part is to understand **how** they work, **when** to create them, and for **which columns**.\n"
  },
  {
    "path": "docs/tutorial/insert.md",
    "content": "# Create Rows - Use the Session - INSERT\n\nNow that we have a database and a table, we can start adding data.\n\nHere's a reminder of how the table would look like, this is the data we want to add:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n## Create Table and Database\n\nWe will continue from where we left off in the last chapter.\n\nThis is the code we had to create the database and table, nothing new here:\n\n//// tab | Python 3.10+\n\n```{.python .annotate hl_lines=\"20\" }\n{!./docs_src/tutorial/create_db_and_table/tutorial003_py310.py[ln:1-18]!}\n\n# More code here later 👈\n\n{!./docs_src/tutorial/create_db_and_table/tutorial003_py310.py[ln:21-22]!}\n```\n\n{!./docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md!}\n\n////\n\nNow that we can create the database and the table, we will continue from this point and add more code on the same file to create the data.\n\n## Create Data with SQL\n\nBefore working with Python code, let's see how we can create data with SQL.\n\nLet's say we want to insert the record/row for `Deadpond` into our database.\n\nWe can do this with the following SQL code:\n\n```SQL\nINSERT INTO \"hero\" (\"name\", \"secret_name\")\nVALUES (\"Deadpond\", \"Dive Wilson\");\n```\n\nIt means, more or less:\n\n> Hey SQL database 👋, please `INSERT` something (create a record/row) `INTO` the table `\"hero\"`.\n>\n> I want you to insert a row with some values in these specific columns:\n>\n> * `\"name\"`\n> * `\"secret_name\"`\n>\n> And the values I want you to put in these columns are:\n>\n> * `\"Deadpond\"`\n> * `\"Dive Wilson\"`\n\n### Try it in DB Explorer for SQLite\n\nYou can try that SQL statement in **DB Explorer for SQLite**.\n\nMake sure to open the same database we already created by clicking <kbd>Open Database</kbd> and selecting the same `database.db` file.\n\n/// tip\n\nIf you don't have that `database.db` file with the table `hero`, you can re-create it by running the Python program at the top. 👆\n\n///\n\nThen go to the <kbd>Execute SQL</kbd> tab and copy the SQL from above.\n\nIt would look like this:\n\n<img class=\"shadow\" src=\"/img/tutorial/insert/image01.png\">\n\nClick the \"Execute all\" <kbd>▶</kbd> button.\n\nThen you can go to the <kbd>Browse Data</kbd> tab, and you will see your newly created record/row:\n\n<img class=\"shadow\" src=\"/img/tutorial/insert/image02.png\">\n\n## Data in a Database and Data in Code\n\nWhen working with a database (SQL or any other type) in a programming language, we will always have some data **in memory**, in objects and variables we create in our code, and there will be some data **in the database**.\n\nWe are constantly **getting** *some* of the data from the database and putting it in memory, in variables.\n\nThe same way, we are constantly **creating** variables and objects with data in our code, that we then want to save in the database, so we **send** it somehow.\n\nIn some cases, we can even create some data in memory and then change it and update it before saving it in the database.\n\nWe might even decide with some logic in the code that we no longer want to save the data in the database, and then just remove it. 🔥 And we only handled that data in memory, without sending it back and forth to the database.\n\n**SQLModel** does all it can (actually via SQLAlchemy) to make this interaction as simple, intuitive, and familiar or \"close to programming\" as possible. ✨\n\nBut that division of the two places where some data might be at each moment in time (in memory or in the database) is always there. And it's important for you to have it in mind. 🤓\n\n## Create Data with Python and **SQLModel**\n\nNow let's create that same row in Python.\n\nFirst, remove that file `database.db` so we can start from a clean slate.\n\nBecause we have Python code executing with data in memory, and the database is an independent system (an external SQLite file, or an external database server), we need to perform two steps:\n\n* create the data in Python, in memory (in a variable)\n* save/send the data to the database\n\n## Create a Model Instance\n\nLet's start with the first step, create the data in memory.\n\nWe already created a class `Hero` that represents the `hero` table in the database.\n\nEach instance we create will represent the data in a row in the database.\n\nSo, the first step is to simply create an instance of `Hero`.\n\nWe'll create 3 right away, for the 3 heroes:\n\n{* ./docs_src/tutorial/insert/tutorial002_py310.py ln[21:24] *}\n\n/// tip\n\nThe code above in this file (the omitted code) is just the same code that you see at the top of this chapter.\n\nThe same code we used before to create the `Hero` model.\n\n///\n\nWe are putting that in a function `create_heroes()`, to call it later once we finish it.\n\nIf you are trying the code interactively, you could also write that directly.\n\n## Create a **Session**\n\nUp to now, we have only used the **engine** to interact with the database.\n\nThe **engine** is that single object that we share with all the code, and that is in charge of communicating with the database, handling the connections (when using a server database like PostgreSQL or MySQL), etc.\n\nBut when working with **SQLModel** you will mostly use another tool that sits on top, the **Session**.\n\nIn contrast to the **engine** that is one for the whole application, we create a new **session** for each group of operations with the database that belong together.\n\nIn fact, the **session** needs and uses an **engine**.\n\nFor example, if we have a web application, we would normally have a single **session** per request.\n\nWe would re-use the same **engine** in all the code, everywhere in the application (shared by all the requests). But for each request, we would create and use a new **session**. And once the request is done, we would close the session.\n\nThe first step is to import the `Session` class:\n\n{* ./docs_src/tutorial/insert/tutorial001_py310.py ln[1] hl[1] *}\n\nThen we can create a new session:\n\n{* ./docs_src/tutorial/insert/tutorial001_py310.py ln[21:26] hl[26] *}\n\nThe new `Session` takes an `engine` as a parameter. And it will use the **engine** underneath.\n\n/// tip\n\nWe will see a better way to create a **session** using a `with` block later.\n\n///\n\n## Add Model Instances to the Session\n\nNow that we have some hero model instances (some objects in memory) and a **session**, the next step is to add them to the session:\n\n{* ./docs_src/tutorial/insert/tutorial001_py310.py ln[21:30] hl[28:30] *}\n\nBy this point, our heroes are *not* stored in the database yet.\n\nAnd this is one of the cases where having a **session** independent of an **engine** makes sense.\n\nThe session is holding in memory all the objects that should be saved in the database later.\n\nAnd once we are ready, we can **commit** those changes, and then the **session** will use the **engine** underneath to save all the data by sending the appropriate SQL to the database, and that way it will create all the rows. All in a single batch.\n\nThis makes the interactions with the database more efficient (plus some extra benefits).\n\n/// info  | Technical Details\n\nThe session will create a new transaction and execute all the SQL code in that transaction.\n\nThis ensures that the data is saved in a single batch, and that it will all succeed or all fail, but it won't leave the database in a broken state.\n\n///\n\n## Commit the Session Changes\n\nNow that we have the heroes in the **session** and that we are ready to save all that to the database, we can **commit** the changes:\n\n{* ./docs_src/tutorial/insert/tutorial001_py310.py ln[21:32] hl[32] *}\n\nOnce this line is executed, the **session** will use the **engine** to save all the data in the database by sending the corresponding SQL.\n\n## Create Heroes as a Script\n\nThe function to create the heroes is now ready.\n\nNow we just need to make sure to call it when we run this program with Python directly.\n\nWe already had a main block like:\n\n```Python\nif __name__ == \"__main__\":\n    create_db_and_tables()\n```\n\nWe could add the new function there, as:\n\n```Python\nif __name__ == \"__main__\":\n    create_db_and_tables()\n    create_heroes()\n```\n\nBut to keep things a bit more organized, let's instead create a new function `main()` that will contain all the code that should be executed when called as an independent script, and we can put there the previous function `create_db_and_tables()`, and add the new function `create_heroes()`:\n\n{* ./docs_src/tutorial/insert/tutorial002_py310.py ln[34:36] hl[34,36] *}\n\nAnd then we can call that single `main()` function from that main block:\n\n{* ./docs_src/tutorial/insert/tutorial002_py310.py ln[34:40] hl[40] *}\n\nBy having everything that should happen when called as a script in a single function, we can easily add more code later on.\n\nAnd some other code could also import and use this same `main()` function if it was necessary.\n\n## Run the Script\n\nNow we can run our program as a script from the console.\n\nBecause we created the **engine** with `echo=True`, it will print out all the SQL code that it is executing:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n// Some boilerplate, checking that the hero table already exists\nINFO Engine BEGIN (implicit)\nINFO Engine PRAGMA main.table_info(\"hero\")\nINFO Engine [raw sql] ()\nINFO Engine COMMIT\n// BEGIN a transaction automatically ✨\nINFO Engine BEGIN (implicit)\n// Our INSERT statement, it uses VALUES (?, ?, ?) as parameters\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\n// ...and these are the parameter values 🚀\nINFO Engine [generated in 0.00013s] ('Deadpond', 'Dive Wilson', None)\n// Again, for Spider-Boy\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.000755s ago] ('Spider-Boy', 'Pedro Parqueador', None)\n// And now for Rusty-Man\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001014s ago] ('Rusty-Man', 'Tommy Sharp', 48)\n// All good? Yes, commit this transaction! 🎉\nINFO Engine COMMIT\n```\n\n</div>\n\nIf you have ever used Git, this works very similarly.\n\nWe use `session.add()` to add new objects (model instances) to the session (similar to `git add`).\n\nAnd that ends up in a group of data ready to be saved, but not saved yet.\n\nWe can make more modifications, add more objects, etc.\n\nAnd once we are ready, we can **commit** all the changes in a single step (similar to `git commit`).\n\n## Close the Session\n\nThe **session** holds some resources, like connections from the engine.\n\nSo once we are done with the session, we should **close** it to make it release those resources and finish its cleanup:\n\n{* ./docs_src/tutorial/insert/tutorial001_py310.py ln[21:34] hl[34] *}\n\nBut what happens if we forget to close the session?\n\nOr if there's an exception in the code and it never reaches the `session.close()`?\n\nFor that, there's a better way to create and close the session, using a `with` block. 👇\n\n## A Session in a `with` Block\n\nIt's good to know how the `Session` works and how to create and close it manually. It might be useful if, for example, you want to explore the code in an interactive session (for example with Jupyter).\n\nBut there's a better way to handle the session, using a `with` block:\n\n{* ./docs_src/tutorial/insert/tutorial002_py310.py ln[21:31] hl[26:31] *}\n\nThis is the same as creating the session manually and then manually closing it. But here, using a `with` block, it will be automatically created when **starting** the `with` block and assigned to the variable `session`, and it will be automatically closed after the `with` block is **finished**.\n\nAnd it will work even if there's an exception in the code. 😎\n\n## Review All the Code\n\nLet's give this whole file a final look. 🔍\n\nYou already know all of the first part for creating the `Hero` model class, the **engine**, and creating the database and table.\n\nLet's focus on the new code:\n\n//// tab | Python 3.10+\n\n```{.python .annotate }\n{!./docs_src/tutorial/insert/tutorial003_py310.py!}\n```\n\n{!./docs_src/tutorial/insert/annotations/en/tutorial003.md!}\n\n////\n\n/// tip\n\nReview what each line does by clicking each number bubble in the code. 👆\n\n///\n\nYou can now put it in a `app.py` file and run it with Python. And you will see an output like the one shown above.\n\nAfter that, if you open the database with **DB Browser for SQLite**, you will see the data you just created in the <kbd>Browse Data</kbd> tab:\n\n<img class=\"shadow\" src=\"/img/tutorial/insert/image03.png\">\n\n## What's Next\n\nNow you know how to add rows to the database. 🎉\n\nNow is a good time to understand better why the `id` field **can't be `NULL`** on the database because it's a **primary key**, but actually **can be `None`** in the Python code.\n\nI'll tell you about that in the next chapter. 🚀\n"
  },
  {
    "path": "docs/tutorial/limit-and-offset.md",
    "content": "# Read a Range of Data - LIMIT and OFFSET\n\nNow you know how to get a single row with `.one()`, `.first()`, and `session.get()`.\n\nAnd you also know how to get multiple rows while filtering them using `.where()`.\n\nNow let's see how to get only a **range of results**.\n\n<img class=\"shadow\" alt=\"table with first 3 rows selected\" src=\"/img/tutorial/offset-and-limit/limit.drawio.svg\">\n\n## Create Data\n\nWe will continue with the same code as before, but we'll modify the `select_heroes()` function to simplify the example and focus on what we want to achieve here.\n\nAgain, we will create several heroes to have some data to select from:\n\n{* ./docs_src/tutorial/offset_and_limit/tutorial001_py310.py ln[21:39] hl[22:28] *}\n\n## Review Select All\n\nThis is the code we had to select all the heroes in the `select()` examples:\n\n{* ./docs_src/tutorial/select/tutorial003_py310.py ln[34:39] hl[34:39] *}\n\nBut this would get us **all** the heroes at the same time, in a database that could have thousands, that could be problematic.\n\n## Select with Limit\n\nWe currently have 7 heroes in the database. But we could as well have thousands, so let's limit the results to get only the first 3:\n\n{* ./docs_src/tutorial/offset_and_limit/tutorial001_py310.py ln[42:47] hl[44] *}\n\nThe special **select** object we get from `select()` also has a method `.limit()` that we can use to limit the results to a certain number.\n\nIn this case, instead of getting all the 7 rows, we are limiting them to only get the first 3.\n\n<img class=\"shadow\" alt=\"table with first 3 rows selected\" src=\"/img/tutorial/offset-and-limit/limit.drawio.svg\">\n\n## Run the Program on the Command Line\n\nIf we run it on the command line, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Select with LIMIT\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\n LIMIT ? OFFSET ?\nINFO Engine [no key 0.00014s] (3, 0)\n\n// Print the heroes received, only 3\n[\n    Hero(age=None, secret_name='Dive Wilson', id=1, name='Deadpond'),\n    Hero(age=None, secret_name='Pedro Parqueador', id=2, name='Spider-Boy'),\n    Hero(age=48, secret_name='Tommy Sharp', id=3, name='Rusty-Man')\n]\n```\n\n</div>\n\nGreat! We got only 3 heroes as we wanted.\n\n/// tip\n\nWe will check out that SQL code more in a bit.\n\n///\n\n## Select with Offset and Limit\n\nNow we can limit the results to get only the first 3.\n\nBut imagine we are in a user interface showing the results in batches of 3 heroes at a time.\n\n/// tip\n\nThis is commonly called \"pagination\". Because the user interface would normally show a \"page\" of a predefined number of heroes at a time.\n\nAnd then you can interact with the user interface to get the next page, and so on.\n\n///\n\nHow do we get the next 3?\n\n<img class=\"shadow\" alt=\"table with next rows selected, from 4 to 6\" src=\"/img/tutorial/offset-and-limit/limit2.drawio.svg\">\n\nWe can use `.offset()`:\n\n{* ./docs_src/tutorial/offset_and_limit/tutorial002_py310.py ln[42:47] hl[44] *}\n\nThe way this works is that the special **select** object we get from `select()` has methods like `.where()`, `.offset()` and `.limit()`.\n\nEach of those methods applies the change in the internal special select statement object, and also **return the same object**, this way, we can continue using more methods on it, like in the example above that we use both `.offset()` and `.limit()`.\n\n**Offset** means \"skip this many rows\", and as we want to skip the ones we already saw, the first three, we use `.offset(3)`.\n\n## Run the Program with Offset on the Command Line\n\nNow we can run the program on the command line, and it will output:\n\n<div class=\"termy\">\n\n```console\n$python app.py\n\n// Previous output omitted 🙈\n\n// Select with LIMIT and OFFSET\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\n LIMIT ? OFFSET ?\nINFO Engine [no key 0.00020s] (3, 3)\n\n// Print the 3 heroes received, the second batch\n[\n    Hero(age=32, secret_name='Natalia Roman-on', id=4, name='Tarantula'),\n    Hero(age=35, secret_name='Trevor Challa', id=5, name='Black Lion'),\n    Hero(age=36, secret_name='Steve Weird', id=6, name='Dr. Weird')\n]\n```\n\n</div>\n\n## Select Next Batch\n\nThen to get the next batch of 3 rows we would offset all the ones we already saw, the first 6:\n\n{* ./docs_src/tutorial/offset_and_limit/tutorial003_py310.py ln[42:47] hl[44] *}\n\nThe database right now has **only 7 rows**, so this query can only get 1 row.\n\n<img class=\"shadow\" alt=\"table with the last row (7th) selected\" src=\"/img/tutorial/offset-and-limit/limit3.drawio.svg\">\n\nBut don't worry, the database won't throw an error trying to get 3 rows when there's only one (as would happen with a Python list).\n\nThe database knows that we want to **limit** the number of results, but it doesn't necessarily have to find that many results.\n\n## Run the Program with the Last Batch on the Command Line\n\nAnd if we run it in the command line, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Select last batch with LIMIT and OFFSET\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\n LIMIT ? OFFSET ?\nINFO Engine [no key 0.00038s] (3, 6)\n\n// Print last batch of heroes, only one\n[\n    Hero(age=93, secret_name='Esteban Rogelios', id=7, name='Captain North America')\n]\n```\n\n</div>\n\n## SQL with LIMIT and OFFSET\n\nYou probably noticed the new SQL keywords `LIMIT` and `OFFSET`.\n\nYou can use them in SQL, at the end of the other parts:\n\n```SQL\nSELECT id, name, secret_name, age\nFROM hero\nLIMIT 3 OFFSET 6\n```\n\nIf you try that in **DB Browser for SQLite**, you will get the same result:\n\n<img class=\"shadow\" alt=\"DB Browser for SQLite showing the result of the SQL query\" src=\"/img/tutorial/offset-and-limit/db-browser.png\">\n\n## Combine Limit and Offset with Where\n\nOf course, you can also combine `.limit()` and `.offset()` with `.where()` and other methods you will learn about later:\n\n{* ./docs_src/tutorial/offset_and_limit/tutorial004_py310.py ln[42:47] hl[44] *}\n\n## Run the Program with Limit, Offset, and Where on the Command Line\n\nIf we run it on the command line, it will find all the heroes in the database with an age above 32. That would normally be 4 heroes.\n\nBut we are starting to include after an offset of 1 (so we don't count the first one), and we are limiting the results to only get the first 2 after that:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Select with WHERE and LIMIT and OFFSET\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age > ?\n LIMIT ? OFFSET ?\nINFO Engine [no key 0.00022s] (32, 2, 1)\n\n// Print the heroes received, only 2\n[\n    Hero(age=36, id=6, name='Dr. Weird', secret_name='Steve Weird'),\n    Hero(age=48, id=3, name='Rusty-Man', secret_name='Tommy Sharp')\n]\n```\n\n</div>\n\n## Recap\n\nIndependently of how you filter the data with `.where()` or other methods, you can limit the query to get at maximum some number of results with `.limit()`.\n\nAnd the same way, you can skip the first results with `.offset()`.\n"
  },
  {
    "path": "docs/tutorial/many-to-many/create-data.md",
    "content": "# Create Data with Many-to-Many Relationships\n\nLet's continue from where we left and create some data.\n\nWe'll create data for this same **many-to-many** relationship with a link table:\n\n<img alt=\"many-to-many table relationships\" src=\"/img/tutorial/many-to-many/many-to-many.drawio.svg\">\n\nWe'll continue from where we left off with the previous code.\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[0] *}\n\n## Create Heroes\n\nAs we have done before, we'll create a function `create_heroes()` and we'll create some teams and heroes in it:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[36:54] hl[44] *}\n\nThis is very similar to what we have done before.\n\nWe create a couple of teams, and then three heroes.\n\nThe only new detail is that instead of using an argument `team` we now use `teams`, because that is the name of the new **relationship attribute**. And more importantly, we pass a **list of teams** (even if it contains a single team).\n\nSee how **Deadpond** now belongs to the two teams?\n\n## Commit, Refresh, and Print\n\nNow let's do as we have done before, `commit` the **session**, `refresh` the data, and print it:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[36:69] hl[55:58,60:62,64:69] *}\n\n## Add to Main\n\nAs before, add the `create_heroes()` function to the `main()` function to make sure it is called when running this program from the command line:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[72:74] *}\n\n## Run the Program\n\nIf we run the program from the command line, it would output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n// Insert the hero data first\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00041s] ('Deadpond', 'Dive Wilson', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001942s ago] ('Rusty-Man', 'Tommy Sharp', 48)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.002541s ago] ('Spider-Boy', 'Pedro Parqueador', None)\n// Insert the team data second\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [generated in 0.00037s] ('Z-Force', 'Sister Margaret's Bar')\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [cached since 0.001239s ago] ('Preventers', 'Sharp Tower')\n// Insert the link data last, to be able to re-use the created IDs\nINFO Engine INSERT INTO heroteamlink (team_id, hero_id) VALUES (?, ?)\nINFO Engine [generated in 0.00026s] ((2, 3), (1, 1), (2, 1), (2, 2))\n// Commit and save the data in the database\nINFO Engine COMMIT\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n// Refresh the data\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00019s] (1,)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.001959s ago] (2,)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.003215s ago] (3,)\n\n// Print Deadpond\nDeadpond: name='Deadpond' age=None id=1 secret_name='Dive Wilson'\n\n// Accessing the .team attribute triggers a refresh\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team, heroteamlink\nWHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id\nINFO Engine [generated in 0.00025s] (1,)\n\n// Print Deadpond's teams, 2 teams! 🎉\nDeadpond teams: [Team(id=1, name='Z-Force', headquarters='Sister Margaret's Bar'), Team(id=2, name='Preventers', headquarters='Sharp Tower')]\n\n// Print Rusty-Man\nRusty-Man: name='Rusty-Man' age=48 id=2 secret_name='Tommy Sharp'\n\n// Accessing the .team attribute triggers a refresh\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team, heroteamlink\nWHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id\nINFO Engine [cached since 0.001716s ago] (2,)\n\n// Print Rusty-Man teams, just one, but still a list\nRusty-Man Teams: [Team(id=2, name='Preventers', headquarters='Sharp Tower')]\n\n// Print Spider-Boy\nSpider-Boy: name='Spider-Boy' age=None id=3 secret_name='Pedro Parqueador'\n\n// Accessing the .team attribute triggers a refresh\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team, heroteamlink\nWHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id\nINFO Engine [cached since 0.002739s ago] (3,)\n\n// Print Spider-Boy's teams, just one, but still a list\nSpider-Boy Teams: [Team(id=2, name='Preventers', headquarters='Sharp Tower')]\n\n// Automatic roll back any previous automatic transaction, at the end of the with block\nINFO Engine ROLLBACK\n```\n\n</div>\n\n## Recap\n\nAfter setting up the model link, using it with **relationship attributes** is fairly straightforward, just Python objects. ✨\n"
  },
  {
    "path": "docs/tutorial/many-to-many/create-models-with-link.md",
    "content": "# Create Models with a Many-to-Many Link\n\nWe'll now support **many-to-many** relationships using a **link table** like this:\n\n<img alt=\"many-to-many table relationships\" src=\"/img/tutorial/many-to-many/many-to-many.drawio.svg\">\n\nLet's start by defining the class models, including the **link table** model.\n\n## Link Table Model\n\nAs we want to support a **many-to-many** relationship, now we need a **link table** to connect them.\n\nWe can create it just as any other **SQLModel**:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[1:6] hl[4:6] *}\n\nThis is a **SQLModel** class model table like any other.\n\nIt has two fields, `team_id` and `hero_id`.\n\nThey are both **foreign keys** to their respective tables. We'll create those models in a second, but you already know how that works.\n\nAnd **both fields are primary keys**. We hadn't used this before. 🤓\n\n## Team Model\n\nLet's see the `Team` model, it's almost identical as before, but with a little change:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[9:14] hl[14] *}\n\nThe **relationship attribute `heroes`** is still a list of heroes, annotated as `list[\"Hero\"]`. Again, we use `\"Hero\"` in quotes because we haven't declared that class yet by this point in the code (but as you know, editors and **SQLModel** understand that).\n\nWe use the same **`Relationship()`** function.\n\nWe use **`back_populates=\"teams\"`**. Before we referenced an attribute `team`, but as now we can have many, we'll rename it to `teams` when creating the `Hero` model.\n\nAnd here's the important part to allow the **many-to-many** relationship, we use **`link_model=HeroTeamLink`**. That's it. ✨\n\n## Hero Model\n\nLet's see the other side, here's the `Hero` model:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[17:23] hl[23] *}\n\nWe **removed** the previous `team_id` field (column) because now the relationship is done via the link table. 🔥\n\nThe relationship attribute is now named **`teams`** instead of `team`, as now we support multiple teams.\n\nIt no longer has a type of `Team | None` but a list of teams, the type is now declared as **`list[Team]`**.\n\nWe are using the **`Relationship()`** here too.\n\nWe still have **`back_populates=\"heroes\"`** as before.\n\nAnd now we have a **`link_model=HeroTeamLink`**. ✨\n\n## Create the Tables\n\nThe same as before, we will have the rest of the code to create the **engine**, and a function to create all the tables `create_db_and_tables()`.\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[26:33] hl[32] *}\n\nAnd as in previous examples, we will add that function to a function `main()`, and we will call that `main()` function in the main block:\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[72:73,77:78] hl[73] *}\n\n## Run the Code\n\nIf you run the code in the command line, it would output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Boilerplate omitted 😉\n\nINFO Engine\nCREATE TABLE team (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        headquarters VARCHAR NOT NULL,\n        PRIMARY KEY (id)\n)\n\n\nINFO Engine [no key 0.00033s] ()\nINFO Engine\nCREATE TABLE hero (\n        id INTEGER,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        PRIMARY KEY (id)\n)\n\n\nINFO Engine [no key 0.00016s] ()\nINFO Engine\n\n// Our shinny new link table ✨\nCREATE TABLE heroteamlink (\n        team_id INTEGER,\n        hero_id INTEGER,\n        PRIMARY KEY (team_id, hero_id),\n        FOREIGN KEY(team_id) REFERENCES team (id),\n        FOREIGN KEY(hero_id) REFERENCES hero (id)\n)\n\n\nINFO Engine [no key 0.00031s] ()\nINFO Engine COMMIT\n\n```\n\n</div>\n\n## Recap\n\nWe can support **many-to-many** relationships between tables by declaring a link table.\n\nWe can create it the same way as with other **SQLModel** classes, and then use it in the `link_model` parameter to `Relationship()`.\n\nNow let's work with data using these models in the next chapters. 🤓\n"
  },
  {
    "path": "docs/tutorial/many-to-many/index.md",
    "content": "# Many to Many - Intro\n\nWe saw how to work with <abbr title=\"Also called Many-to-One\">One-to-Many</abbr> relationships in the data.\n\nBut how do you handle **Many-to-Many** relationships?\n\nLet's explore them. 🚀\n\n## Starting from One-to-Many\n\nLet's start with the familiar and simpler option of **One-to-Many**.\n\nWe have one table with teams and one with heroes, and for each **one** team, we can have **many** heroes.\n\nAs each team could have multiple heroes, we wouldn't be able to put the Hero IDs in columns for all of them in the `team` table.\n\nBut as each hero can belong **only to one** team, we have a **single column** in the heroes table to point to the specific team (to a specific row in the `team` table).\n\nThe `team` table looks like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\n/// tip\n\nNotice that it doesn't have any foreign key to other tables.\n\n///\n\nAnd the `hero` table looks like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n</table>\n\nWe have a column in the `hero` table for the `team_id` that points to the ID of a specific team in the `team` table.\n\nThis is how we connect each `hero` with a `team`:\n\n<img alt=\"table relationships\" src=\"/img/databases/relationships.drawio.svg\">\n\nNotice that each hero can only have **one** connection. But each team can receive **many** connections. In particular, the team **Preventers** has two heroes.\n\n## Introduce Many-to-Many\n\nBut let's say that as **Deadpond** is a great character, they recruit him to the new **Preventers** team, but he's still part of the **Z-Force** team too.\n\nSo, now, we need to be able to have a hero that is connected to **many** teams. And then, each team, should still be able to receive **many** heroes. So we need a **Many-to-Many** relationship.\n\nA naive approach that wouldn't work very well is to add more columns to the `hero` table. Imagine we add two extra columns. Now we could connect a single `hero` to 3 teams in total, but not more. So we haven't really solved the problem of supporting **many** teams, only a very limited fixed number of teams.\n\nWe can do better! 🤓\n\n## Link Table\n\nWe can create another table that would represent the link between the `hero` and `team` tables.\n\nAll this table contains is two columns, `hero_id` and `team_id`.\n\nBoth columns are **foreign keys** pointing to the ID of a specific row in the `hero` and `team` tables.\n\nAs this will represent the **hero-team-link**, let's call the table `heroteamlink`.\n\nIt would look like this:\n\n<img alt=\"many-to-many table relationships\" src=\"/img/tutorial/many-to-many/many-to-many.drawio.svg\">\n\nNotice that now the table `hero` **doesn't have a `team_id`** column anymore, it is replaced by this link table.\n\nAnd the `team` table, just as before, doesn't have any foreign key either.\n\nSpecifically, the new link table `heroteamlink` would be:\n\n<table>\n<tr>\n<th>hero_id</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>1</td>\n</tr>\n<tr>\n<td>1</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>1</td>\n</tr>\n</table>\n\n/// info\n\nOther names used for this **link table** are:\n\n* association table\n* secondary table\n* junction table\n* intermediate table\n* join table\n* through table\n* relationship table\n* connection table\n\nI'm using the term \"link table\" because it's short, doesn't collide with other terms already used (e.g. \"relationship\"), it's easy to remember how to write it, etc.\n\n///\n\n## Link Primary Key\n\nCool, we have a link table with **just two columns**. But remember that SQL databases [require each row to have a **primary key**](../../databases.md#identifications-primary-key){.internal-link target=_blank} that **uniquely identifies** the row in that table?\n\nNow, what is the **primary key** in this table?\n\nHow to we identify each unique row?\n\nShould we add another column just to be the **primary key** of this link table? Nope! We don't have to do that. 👌\n\n**Both columns are the primary key** of each row in this table (and each row just has those two columns). ✨\n\nA primary key is a way to **uniquely identify** a particular row in a **single table**. But it doesn't have to be a single column.\n\nA primary key can be a group of the columns in a table, which combined are unique in this table.\n\nCheck the table above again, see that **each row has a unique combination** of `hero_id` and `team_id`?\n\nWe cannot have duplicated primary keys, which means that we cannot have duplicated links between `hero` and `team`, exactly what we want!\n\nFor example, the database will now prevent an error like this, with a duplicated row:\n\n<table>\n<tr>\n<th>hero_id</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>1</td>\n</tr>\n<tr>\n<td>1</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>1</td>\n</tr>\n<tr>\n<td>3 🚨</td><td>1 🚨</td>\n</tr>\n</table>\n\nIt wouldn't make sense to have a hero be part of the **same team twice**, right?\n\nNow, just by using the two columns as the primary keys of this table, SQL will take care of **preventing us from duplicating** a link between `hero` and `team`. ✅\n\n## Recap\n\nAn intro with a recap! That's weird... but anyway. 🤷\n\nNow you have the theory about the **many-to-many** relationships, and how to solve them with tables in SQL. 🤓\n\nNow let's check how to write the SQL and the code to work with them. 🚀\n"
  },
  {
    "path": "docs/tutorial/many-to-many/link-with-extra-fields.md",
    "content": "# Link Model with Extra Fields\n\nIn the previous example we never interacted directly with the `HeroTeamLink` model, it was all through the automatic **many-to-many** relationship.\n\nBut what if we needed to have additional data to describe the link between the two models?\n\nLet's say that we want to have an extra field/column to say if a hero **is still training** in that team or if they are already going on missions and stuff.\n\nLet's see how to achieve that.\n\n## Link Model with Two One-to-Many\n\nThe way to handle this is to explicitly use the link model, to be able to get and modify its data (apart from the foreign keys pointing to the two models for `Hero` and `Team`).\n\nIn the end, the way it works is just like two **one-to-many** relationships combined.\n\nA row in the table `heroteamlink` points to **one** particular hero, but a single hero can be connected to **many** hero-team links, so it's **one-to-many**.\n\nAnd also, the same row in the table `heroteamlink` points to **one** team, but a single team can be connected to **many** hero-team links, so it's also **one-to-many**.\n\n/// tip\n\nThe previous many-to-many relationship was also just two one-to-many relationships combined, but now it's going to be much more explicit.\n\n///\n\n## Update Link Model\n\nLet's update the `HeroTeamLink` model.\n\nWe will add a new field `is_training`.\n\nAnd we will also add two **relationship attributes**, for the linked `team` and `hero`:\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[4:10] hl[7,9:10] *}\n\nThe new **relationship attributes** have their own `back_populates` pointing to new relationship attributes we will create in the `Hero` and `Team` models:\n\n* `team`: has `back_populates=\"hero_links\"`, because in the `Team` model, the attribute will contain the links to the **team's heroes**.\n* `hero`: has `back_populates=\"team_links\"`, because in the `Hero` model, the attribute will contain the links to the **hero's teams**.\n\n/// info\n\nIn SQLAlchemy this is called an Association Object or Association Model.\n\nI'm calling it **Link Model** just because that's easier to write avoiding typos. But you are also free to call it however you want. 😉\n\n///\n\n## Update Team Model\n\nNow let's update the `Team` model.\n\nWe no longer have the `heroes` relationship attribute, and instead we have the new `hero_links` attribute:\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[13:18] hl[18] *}\n\n## Update Hero Model\n\nThe same with the `Hero` model.\n\nWe change the `teams` relationship attribute for `team_links`:\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[21:27] hl[27] *}\n\n## Create Relationships\n\nNow the process to create relationships is very similar.\n\nBut now we create the **explicit link models** manually, pointing to their hero and team instances, and specifying the additional link data (`is_training`):\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[40:79] hl[58:67,69:72] *}\n\nWe are just adding the link model instances to the session, because the link model instances are connected to the heroes and teams, they will be also automatically included in the session when we commit.\n\n## Run the Program\n\nNow, if we run the program, it will show almost the same output as before, because it is generating almost the same SQL, but this time including the new `is_training` column:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Insert the heroes\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00025s] ('Deadpond', 'Dive Wilson', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.00136s ago] ('Spider-Boy', 'Pedro Parqueador', None)\nINFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\nINFO Engine [cached since 0.001858s ago] ('Rusty-Man', 'Tommy Sharp', 48)\n\n// Insert the teams\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [generated in 0.00019s] ('Z-Force', 'Sister Margaret's Bar')\nINFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)\nINFO Engine [cached since 0.0007985s ago] ('Preventers', 'Sharp Tower')\n\n// Insert the hero-team links\nINFO Engine INSERT INTO heroteamlink (team_id, hero_id, is_training) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00023s] ((1, 1, 0), (2, 1, 1), (2, 2, 1), (2, 3, 0))\n// Save the changes in the transaction in the database\nINFO Engine COMMIT\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Automatically fetch the data on attribute access\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [generated in 0.00028s] (1,)\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.team_id\nINFO Engine [generated in 0.00026s] (1,)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00024s] (1,)\n\n// Print Z-Force hero data, including link data\nZ-Force hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: False\n\n// Automatically fetch the data on attribute access\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [cached since 0.008822s ago] (2,)\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.team_id\nINFO Engine [cached since 0.005778s ago] (2,)\n\n// Print Preventers hero data, including link data\nPreventers hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: True\n\n// Automatically fetch the data on attribute access\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.004196s ago] (2,)\n\n// Print Preventers hero data, including link data\nPreventers hero: name='Spider-Boy' age=None id=2 secret_name='Pedro Parqueador' is training: True\n\n// Automatically fetch the data on attribute access\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.006005s ago] (3,)\n\n// Print Preventers hero data, including link data\nPreventers hero: name='Rusty-Man' age=48 id=3 secret_name='Tommy Sharp' is training: False\n```\n\n</div>\n\n## Add Relationships\n\nNow, to add a new relationship, we have to create a new `HeroTeamLink` instance pointing to the hero and the team, add it to the session, and commit it.\n\nHere we do that in the `update_heroes()` function:\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[82:97] hl[89:94] *}\n\n## Run the Program with the New Relationship\n\nIf we run that program, we will see the output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Select the hero\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00014s] ('Spider-Boy',)\n\n// Select the team\nINFO Engine SELECT team.id, team.name, team.headquarters\nFROM team\nWHERE team.name = ?\nINFO Engine [no key 0.00012s] ('Z-Force',)\n\n// Create the link\nINFO Engine INSERT INTO heroteamlink (team_id, hero_id, is_training) VALUES (?, ?, ?)\nINFO Engine [generated in 0.00023s] (1, 2, 1)\n\n// Automatically refresh the data on attribute access\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.team_id\nINFO Engine [cached since 0.01514s ago] (1,)\nINFO Engine COMMIT\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.08953s ago] (2,)\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.hero_id\nINFO Engine [generated in 0.00018s] (2,)\n\n// Print updated hero links\nUpdated Spider-Boy's Teams: [\n    HeroTeamLink(team_id=2, is_training=True, hero_id=2),\n    HeroTeamLink(team_id=1, is_training=True, hero_id=2)\n]\n\n// Automatically refresh team data on attribute access\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [cached since 0.1084s ago] (1,)\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.team_id\nINFO Engine [cached since 0.1054s ago] (1,)\n\n// Print team hero links\nZ-Force heroes: [\n    HeroTeamLink(team_id=1, is_training=False, hero_id=1),\n    HeroTeamLink(team_id=1, is_training=True, hero_id=2)\n]\n```\n\n</div>\n\n## Update Relationships with Links\n\nNow let's say that **Spider-Boy** has been training enough in the **Preventers**, and they say he can join the team full time.\n\nSo now we want to update the status of `is_training` to `False`.\n\nWe can do that by iterating on the links:\n\n{* ./docs_src/tutorial/many_to_many/tutorial003_py310.py ln[82:83,99:107] hl[99:101] *}\n\n## Run the Program with the Updated Relationships\n\nAnd if we run the program now, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Automatically fetch team data on attribute access\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [generated in 0.00015s] (2,)\n\n// Update link row\nINFO Engine UPDATE heroteamlink SET is_training=? WHERE heroteamlink.team_id = ? AND heroteamlink.hero_id = ?\nINFO Engine [generated in 0.00020s] (0, 2, 2)\n\n// Save current transaction to database\nINFO Engine COMMIT\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Automatically fetch data on attribute access\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.2004s ago] (2,)\nINFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training\nFROM heroteamlink\nWHERE ? = heroteamlink.hero_id\nINFO Engine [cached since 0.1005s ago] (2,)\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [cached since 0.09707s ago] (2,)\n\n// Print Spider-Boy team, including link data, if is training\nSpider-Boy team: headquarters='Sharp Tower' id=2 name='Preventers' is training: False\n\n// Automatically fetch data on attribute access\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [cached since 0.2097s ago] (1,)\n\n// Print Spider-Boy team, including link data, if is training\nSpider-Boy team: headquarters='Sister Margaret's Bar' id=1 name='Z-Force' is training: True\nINFO Engine ROLLBACK\n```\n\n</div>\n\n## Recap\n\nIf you need to store more information about a **many-to-many** relationship you can use an explicit link model with extra data in it. 🤓\n"
  },
  {
    "path": "docs/tutorial/many-to-many/update-remove-relationships.md",
    "content": "# Update and Remove Many-to-Many Relationships\n\nNow we'll see how to update and remove these **many-to-many** relationships.\n\nWe'll continue from where we left off with the previous code.\n\n{* ./docs_src/tutorial/many_to_many/tutorial001_py310.py ln[0] *}\n\n## Get Data to Update\n\nLet's now create a function `update_heroes()`.\n\nWe'll get **Spider-Boy** and the **Z-Force** team.\n\nAs you already know how these goes, I'll use the **short version** and get the data in a single Python statement.\n\nAnd because we are now using `select()`, we also have to import it.\n\n{* ./docs_src/tutorial/many_to_many/tutorial002_py310.py ln[1,72:77] hl[1,72:77] *}\n\nAnd of course, we have to add `update_heroes()` to our `main()` function:\n\n{* ./docs_src/tutorial/many_to_many/tutorial002_py310.py ln[94:101] hl[97] *}\n\n## Add Many-to-Many Relationships\n\nNow let's imagine that **Spider-Boy** thinks that the **Z-Force** team is super cool and decides to go there and join them.\n\nWe can use the same **relationship attributes** to include `hero_spider_boy` in the `team_z_force.heroes`.\n\n{* ./docs_src/tutorial/many_to_many/tutorial002_py310.py ln[72:84] hl[79:81,83:84] *}\n\n/// tip\n\nBecause we are accessing an attribute in the models right after we commit, with `hero_spider_boy.teams` and `team_z_force.heroes`, the data is refreshed automatically.\n\nSo we don't have to call `session.refresh()`.\n\n///\n\nWe then commit the change, refresh, and print the updated **Spider-Boy**'s heroes to confirm.\n\nNotice that we only `add` **Z-Force** to the session, then we commit.\n\nWe never add **Spider-Boy** to the session, and we never even refresh it. But we still print his teams.\n\nThis still works correctly because we are using `back_populates` in the `Relationship()` in the models. That way, **SQLModel** (actually SQLAlchemy) can keep track of the changes and updates, and make sure they also happen on the relationships in the other related models. 🎉\n\n## Run the Program\n\nYou can confirm it's all working by running the program in the command line:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Create the new many-to-many relationship\nINFO Engine INSERT INTO heroteamlink (team_id, hero_id) VALUES (?, ?)\nINFO Engine [generated in 0.00020s] (1, 3)\nINFO Engine COMMIT\n\n// Start a new automatic transaction\nINFO Engine BEGIN (implicit)\n\n// Automatically refresh the data while accessing the attribute .teams\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00044s] (3,)\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team, heroteamlink\nWHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id\nINFO Engine [cached since 0.1648s ago] (3,)\n\n// Print Spider-Boy teams, including Z-Force 🎉\nUpdated Spider-Boy's Teams: [\n    Team(id=2, name='Preventers', headquarters='Sharp Tower'),\n    Team(id=1, name='Z-Force', headquarters='Sister Margaret's Bar')\n]\n\n// Automatically refresh the data while accessing the attribute .heores\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero, heroteamlink\nWHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id\nINFO Engine [cached since 0.1499s ago] (1,)\n\n// Print Z-Force heroes, including Spider-Boy 🎉\nZ-Force heroes: [\n    Hero(name='Deadpond', age=None, id=1, secret_name='Dive Wilson'),\n    Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', teams=[\n        Team(id=2, name='Preventers', headquarters='Sharp Tower'),\n        Team(id=1, name='Z-Force', headquarters='Sister Margaret's Bar', heroes=[...])\n    ])\n]\n```\n\n</div>\n\n## Remove Many-to-Many Relationships\n\nNow let's say that right after joining the team, **Spider-Boy** realized that their \"life preserving policies\" are much more relaxed than what he's used to. 💀\n\nAnd their *occupational safety and health* is also not as great... 💥\n\nSo, **Spider-Boy** decides to leave **Z-Force**.\n\nLet's update the relationships to remove `team_z_force` from `hero_spider_boy.teams`.\n\nBecause `hero_spider_boy.teams` is just a list (a special list managed by SQLAlchemy, but a list), we can use the standard list methods.\n\nIn this case, we use the method `.remove()`, that takes an item and removes it from the list.\n\n{* ./docs_src/tutorial/many_to_many/tutorial002_py310.py ln[72:91] hl[86:88,90:91] *}\n\nAnd this time, just to show again that by using `back_populates` **SQLModel** (actually SQLAlchemy) takes care of connecting the models by their relationships, even though we performed the operation from the `hero_spider_boy` object (modifying `hero_spider_boy.teams`), we are adding `team_z_force` to the **session**. And we commit that, without even add `hero_spider_boy`.\n\nThis still works because by updating the teams in `hero_spider_boy`, because they are synchronized with `back_populates`, the changes are also reflected in `team_z_force`, so it also has changes to be saved in the DB (that **Spider-Boy** was removed).\n\nAnd then we add the team, and commit the changes, which updates the `team_z_force` object, and because it changed the table that also had a connection with the `hero_spider_boy`, it is also marked internally as updated, so it all works.\n\nAnd then we just print them again to confirm that everything worked correctly.\n\n## Run the Program Again\n\nTo confirm that this last part worked, you can run the program again, it will output something like:\n\n<div style=\"font-size: 1rem;\" class=\"termy\">\n\n```console\n$ python app.py\n\n// Previous output omitted 🙈\n\n// Delete the row in the link table\nINFO Engine DELETE FROM heroteamlink WHERE heroteamlink.team_id = ? AND heroteamlink.hero_id = ?\nINFO Engine [generated in 0.00043s] (1, 3)\n// Save the changes\nINFO Engine COMMIT\n\n// Automatically start a new transaction\nINFO Engine BEGIN (implicit)\n\n// Automatically refresh the data while accessing the attribute .heroes\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [generated in 0.00029s] (1,)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero, heroteamlink\nWHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id\nINFO Engine [cached since 0.5625s ago] (1,)\n\n// Print the Z-Force heroes after reverting the changes\nReverted Z-Force's heroes: [\n    Hero(name='Deadpond', age=None, id=1, secret_name='Dive Wilson')\n]\n\n// Automatically refresh the data while accessing the attribute .teams\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [cached since 0.4209s ago] (3,)\nINFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters\nFROM team, heroteamlink\nWHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id\nINFO Engine [cached since 0.5842s ago] (3,)\n\n// Print Spider-Boy's teams after reverting the changes\nReverted Spider-Boy's teams: [\n    Team(id=2, name='Preventers', headquarters='Sharp Tower')\n]\n\n// Automatically roll back any possible previously unsaved transaction\nINFO Engine ROLLBACK\n\n```\n\n</div>\n\n## Recap\n\nUpdating and removing many-to-many relationships is quite straightforward after setting up the **link model** and the relationship attributes.\n\nYou can just use common list operation. 🚀\n"
  },
  {
    "path": "docs/tutorial/one.md",
    "content": "# Read One Row\n\nYou already know how to filter rows to select using `.where()`.\n\nAnd you saw how when executing a `select()` it normally returns an **iterable** object.\n\nOr you can call `results.all()` to get a **list** of all the rows right away, instead of an iterable.\n\nBut in many cases you really just want to read a **single row**, and having to deal with an iterable or a list is not as convenient.\n\nLet's see the utilities to read a single row.\n\n## Continue From Previous Code\n\nWe'll continue with the same examples we have been using in the previous chapters to create and select data and we'll keep updating them.\n\n{* ./docs_src/tutorial/indexes/tutorial002_py310.py ln[0] *}\n\nIf you already executed the previous examples and have a database with data, **remove the database file** before running each example, that way you won't have duplicate data and you will be able to get the same results.\n\n## Read the First Row\n\nWe have been iterating over the rows in a `result` object like:\n\n{* ./docs_src/tutorial/indexes/tutorial002_py310.py ln[42:47] hl[46:47] *}\n\nBut let's say that we are not interested in all the rows, just the **first** one.\n\nWe can call the `.first()` method on the `results` object to get the first row:\n\n{* ./docs_src/tutorial/one/tutorial001_py310.py ln[42:47] hl[46] *}\n\nThis will return the first object in the `results` (if there was any).\n\nThat way, we don't have to deal with an iterable or a list.\n\n/// tip\n\nNotice that `.first()` is a method of the `results` object, not of the `select()` statement.\n\n///\n\nAlthough this query would find two rows, by using `.first()` we get only the first row.\n\nIf we run it in the command line it would output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age <= ?\nINFO Engine [no key 0.00021s] (35,)\n\n// Only print the first item\nHero: secret_name='Natalia Roman-on' age=32 id=4 name='Tarantula'\n```\n\n</div>\n\n## First or `None`\n\nIt would be possible that the SQL query doesn't find any row.\n\nIn that case, `.first()` will return `None`:\n\n{* ./docs_src/tutorial/one/tutorial002_py310.py ln[42:47] hl[44,46] *}\n\nIn this case, as there's no hero with an age less than 25, `.first()` will return `None`.\n\nWhen we run it in the command line it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age <= ?\nINFO Engine [no key 0.00021s] (35,)\n\n// Now rows found, first is None\nHero: None\n```\n\n</div>\n\n## Exactly One\n\nThere might be cases where we want to ensure that there's exactly **one** row matching the query.\n\nAnd if there was more than one, it would mean that there's an error in the system, and we should terminate with an error.\n\nIn that case, instead of `.first()` we can use `.one()`:\n\n{* ./docs_src/tutorial/one/tutorial003_py310.py ln[42:47] hl[46] *}\n\nHere we know that there's only one `\"Deadpond\"`, and there shouldn't be any more than one.\n\nIf we run it once, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00015s] ('Deadpond',)\n\n// Only one row found, we're good ✅\nHero: secret_name='Dive Wilson' age=None id=1 name='Deadpond'\n```\n\n</div>\n\nBut if we run it again, as it will create and insert all the heroes in the database again, they will be duplicated, and there will be more than one `\"Deadpond\"`. 😱\n\nSo, running it again, without first deleting the file `database.db` will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00015s] ('Deadpond',)\n\n// Oh, no, the database is in a broken state, with duplicates! 🚨\nTraceback (most recent call last):\n\n// Some details about the error omitted\n\nsqlalchemy.exc.MultipleResultsFound: Multiple rows were found when exactly one was required\n```\n\n</div>\n\n## Exactly One with More Data\n\nOf course, even if we don't duplicate the data, we could get the same error if we send a query that finds more than one row and expect exactly one with `.one()`:\n\n{* ./docs_src/tutorial/one/tutorial004_py310.py ln[42:47] hl[44,46] *}\n\nThat would find 2 rows, and would end up with the same error.\n\n## Exactly One with No Data\n\nAnd also, if we get no rows at all with `.one()`, it will also raise an error:\n\n{* ./docs_src/tutorial/one/tutorial005_py310.py ln[42:47] hl[44,46] *}\n\nIn this case, as there are no heroes with an age less than 25, `.one()` will raise an error.\n\nThis is what we would get if we run it in the command line:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age < ?\nINFO Engine [no key 0.00014s] (25,)\n\n// Oh, no, we expected one row but there aren't any! 🚨\nTraceback (most recent call last):\n\n// Some details about the error omitted\n\nsqlalchemy.exc.NoResultFound: No row was found when one was required\n```\n\n</div>\n\n## Compact Version\n\nOf course, with `.first()` and `.one()` you would also probably write all that in a more compact form most of the time, all in a single line (or at least a single Python statement):\n\n{* ./docs_src/tutorial/one/tutorial006_py310.py ln[42:45] hl[44] *}\n\nThat would result in the same as some examples above.\n\n## Select by Id with `.where()`\n\nIn many cases you might want to select a single row by its Id column with the **primary key**.\n\nYou could do it the same way we have been doing with a `.where()` and then getting the first item with `.first()`:\n\n{* ./docs_src/tutorial/one/tutorial007_py310.py ln[42:47] hl[44,46] *}\n\nThat would work correctly, as expected. But there's a shorter version. 👇\n\n## Select by Id with `.get()`\n\nAs selecting a single row by its Id column with the **primary key** is a common operation, there's a shortcut for it:\n\n{* ./docs_src/tutorial/one/tutorial008_py310.py ln[42:45] hl[44] *}\n\n`session.get(Hero, 1)` is an equivalent to creating a `select()`, then filtering by Id using `.where()`, and then getting the first item with `.first()`.\n\nIf you run it, it will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// SELECT with WHERE\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00021s] (1,)\n\n// The printed result\nHero: secret_name='Dive Wilson' age=None id=1 name='Deadpond'\n```\n\n</div>\n\n## Select by Id with `.get()` with No Data\n\n`.get()` behaves similar to `.first()`, if there's no data it will simply return `None` (instead of raising an error):\n\n{* ./docs_src/tutorial/one/tutorial009_py310.py ln[42:45] hl[44] *}\n\nRunning that will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// SELECT with WHERE\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00024s] (9001,)\n\n// No data found, so the value is None\nHero: None\n```\n\n</div>\n\n## Recap\n\nAs querying the SQL database for a single row is a common operation, you now have several tools to do it in a short and simple way. 🎉\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/back-populates.md",
    "content": "# Relationship back_populates\n\nNow you know how to use the **relationship attributes** to manipulate connected data in the database! 🎉\n\nLet's now take a small step back and review how we defined those `Relationship()` attributes again, let's clarify that `back_populates` argument. 🤓\n\n## Relationship with `back_populates`\n\nSo, what is that `back_populates` argument in each `Relationship()`?\n\nThe value is a string with the name of the attribute in the **other** model class.\n\n<img src=\"/img/tutorial/relationships/attributes/back-populates.drawio.svg\">\n\nThat tells **SQLModel** that if something changes in this model, it should change that attribute in the other model, and it will work even before committing with the session (that would force a refresh of the data).\n\nLet's understand that better with an example.\n\n## An Incomplete Relationship\n\nLet's see how that works by writing an **incomplete** version first, without `back_populates`:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py ln[1:19] hl[9,19] *}\n\n## Read Data Objects\n\nNow, we will get the **Spider-Boy** hero and, *independently*, the **Preventers** team using two `select`s.\n\nAs you already know how this works, I won't separate that in a select `statement`, `results`, etc. Let's use the shorter form in a single call:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py ln[103:111] hl[105:107,109:111] *}\n\n/// tip\n\nWhen writing your own code, this is probably the style you will use most often, as it's shorter, more convenient, and you still get all the power of autocompletion and inline errors.\n\n///\n\n## Print the Data\n\nNow, let's print the current **Spider-Boy**, the current **Preventers** team, and particularly, the current **Preventers** list of heroes:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py ln[103:115] hl[113:115] *}\n\nUp to this point, it's all good. 😊\n\nIn particular, the result of printing `preventers_team.heroes` is:\n\n``` hl_lines=\"3\"\nPreventers Team Heroes: [\n        Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),\n        Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2),\n        Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),\n        Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),\n        Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)\n]\n```\n\nNotice that we have **Spider-Boy** there.\n\n## Update Objects Before Committing\n\nNow let's update **Spider-Boy**, removing him from the team by setting `hero_spider_boy.team = None` and then let's print this object again:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py ln[103:104,117:121] hl[117,121] *}\n\nThe first important thing is, we *haven't committed* the hero yet, so accessing the list of heroes would not trigger an automatic refresh.\n\nBut in our code, in this exact point in time, we already said that **Spider-Boy** is no longer part of the **Preventers**. 🔥\n\n/// tip\n\nWe could revert that later by not committing the **session**, but that's not what we are interested in here.\n\n///\n\nHere, at this point in the code, in memory, the code expects **Preventers** to *not include* **Spider-Boy**.\n\nThe output of printing `hero_spider_boy` without team is:\n\n```\nSpider-Boy without team: name='Spider-Boy' age=None id=3 secret_name='Pedro Parqueador' team_id=2 team=None\n```\n\nCool, the team is set to `None`, the `team_id` attribute still has the team ID until we save it. But that's okay as we are now working mainly with the **relationship attributes** and the objects. ✅\n\nBut now, what happens when we print the `preventers_team.heroes`?\n\n``` hl_lines=\"3\"\nPreventers Team Heroes again: [\n        Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),\n        Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2, team=None),\n        Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),\n        Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),\n        Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)\n]\n```\n\nOh, no! 😱 **Spider-Boy** is still listed there!\n\n## Commit and Print\n\nNow, if we commit it and print again:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py ln[103:104,123:130] hl[123:124,130] *}\n\nWhen we access `preventers_team.heroes` after the `commit`, that triggers a refresh, so we get the latest list, without **Spider-Boy**, so that's fine again:\n\n```\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id\nFROM hero\nWHERE ? = hero.team_id\n2021-08-13 11:15:24,658 INFO sqlalchemy.engine.Engine [cached since 0.1924s ago] (2,)\n\nPreventers Team Heroes after commit: [\n        Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),\n        Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),\n        Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),\n        Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)\n]\n```\n\nThere's no **Spider-Boy** after committing, so that's good. 😊\n\nBut we still have that inconsistency in that previous point above.\n\nIf we use the objects before committing, we could end up having errors. 😔\n\nLet's fix that. 🤓\n\n## Fix It Using `back_populates`\n\nThat's what `back_populates` is for. ✨\n\nLet's add it back:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py ln[1:19] hl[9,19] *}\n\nAnd we can keep the rest of the code the same:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py ln[103:104,117:121] hl[117,121] *}\n\n/// tip\n\nThis is the same section where we updated `hero_spider_boy.team` to `None` but we *haven't committed* that change yet.\n\nThe same section that caused a problem before.\n\n///\n\n## Review the Result\n\nThis time, **SQLModel** (actually SQLAlchemy) will be able to notice the change, and **automatically update the list of heroes** in the team, even before we commit.\n\nThat second print would output:\n\n```\nPreventers Team Heroes again: [\n        Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),\n        Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),\n        Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),\n        Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)\n]\n```\n\nNotice that now **Spider-Boy** is not there, we fixed it with `back_populates`! 🎉\n\n## The Value of `back_populates`\n\nNow that you know why `back_populates` is there, let's review the exact value again.\n\nIt's quite simple code, it's just a string, but it might be confusing to think exactly *what* string should go there:\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py ln[1:19] hl[9,19] *}\n\nThe string in `back_populates` is the name of the attribute *in the other* model, that will reference *the current* model.\n\n<img src=\"/img/tutorial/relationships/attributes/back-populates.drawio.svg\">\n\nSo, in the class `Team`, we have an attribute `heroes` and we declare it with `Relationship(back_populates=\"team\")`.\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py ln[4:9] hl[9] *}\n\nThe string in `back_populates=\"team\"` refers to the attribute `team` in the class `Hero` (the other class).\n\nAnd, in the class `Hero`, we declare an attribute `team`, and we declare it with `Relationship(back_populates=\"heroes\")`.\n\nSo, the string `\"heroes\"` refers to the attribute `heroes` in the class `Team`.\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py ln[12:19] hl[19] *}\n\n/// tip\n\nEach **relationship attribute** points to the other one, in the other model, using `back_populates`.\n\n///\n\nAlthough it's simple code, it can be confusing to think about 😵, because the same line has concepts related to both models in multiple places:\n\n* Just by being in the **current** model, the line has something to do with the current model.\n* The name of the attribute is about the **other** model.\n* The type annotation is about the **other** model.\n* And the `back_populates` refers to an attribute in the **other** model, that points to the **current** model.\n\n## A Mental Trick to Remember `back_populates`\n\nA mental trick you can use to remember is that the string in `back_populates` is always about the current model class you are editing. 🤓\n\nSo, if you are in the class `Hero`, the value of `back_populates` for any relationship attribute connecting to **any** other table (to any other model, it could be `Team`, `Weapon`, `Powers`, etc) will still always refer to this same class.\n\nSo, `back_populates` would most probably be something like `\"hero\"` or `\"heroes\"`.\n\n<img src=\"/img/tutorial/relationships/attributes/back-populates2.drawio.svg\">\n\n{* ./docs_src/tutorial/relationship_attributes/back_populates/tutorial003_py310.py ln[27:39] hl[27,34,37,39] *}\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/cascade-delete-relationships.md",
    "content": "# Cascade Delete Relationships\n\nWhat happens if we **delete** a team that has a **relationship** with heroes?\n\nShould those heroes be **automatically deleted** too? That's called a \"**cascade**\", because the initial deletion causes a cascade of other deletions.\n\nShould their `team_id` instead be set to `NULL` in the database?\n\nLet's see how to configure that with **SQLModel**.\n\n/// info\n\nThis feature, including `cascade_delete`, `ondelete`, and `passive_deletes`, is available since SQLModel version `0.0.21`.\n\n///\n\n## Initial Heroes and Teams\n\nLet's say that we have these **teams** and **heroes**.\n\n### Team Table\n\n| id   | name       | headquarters          |\n| ---- | ---------- | --------------------- |\n| 1    | Z-Force    | Sister Margaret's Bar |\n| 2    | Preventers | Sharp Tower           |\n| 3    | Wakaland   | Wakaland Capital City |\n\n### Hero Table\n\n| id   | name            | secret_name      | age  | team_id |\n| ---- | --------------- | ---------------- | ---- | ------- |\n| 1    | Deadpond        | Dive WIlson      |      | 1       |\n| 2    | Rusty-Man       | Tommy Sharp      | 48   | 2       |\n| 3    | Spider-Boy      | Pedro Parqueador |      | 2       |\n| 4    | Black Lion      | Trevor Challa    | 35   | 3       |\n| 5    | Princess Sure-E | Sure-E           |      | 3       |\n\n### Visual Teams and Heroes\n\nWe could visualize them like this:\n\n```mermaid\nflowchart TB\n    subgraph \"Z-Force\"\n        d(\"Deadpond\")\n    end\n    subgraph \"Preventers\"\n        r(\"Rusty-Man\")\n        s(\"Spider-Boy\")\n    end\n    subgraph \"Wakaland\"\n        b(\"Black Lion\")\n        p(\"Princess Sure-E\")\n    end\n```\n\n## Delete a Team with Heroes\n\nWhen we **delete a team**, we have to do something with the associated heroes.\n\nBy default, their foreign key pointing to the team will be set to `NULL` in the database.\n\nBut let's say we want the associated heroes to be **automatically deleted**.\n\nFor example, we could delete the team `Wakaland`:\n\n```mermaid\nflowchart TB\n    subgraph zforce[\"Z-Force\"]\n        d(\"Deadpond\")\n    end\n    subgraph preventers[\"Preventers\"]\n        r(\"Rusty-Man\")\n        s(\"Spider-Boy\")\n    end\n    subgraph wakaland[\"Wakaland\"]\n        b(\"Black Lion\")\n        p(\"Princess Sure-E\")\n    end\n      style wakaland fill:#fee,stroke:#900\n```\n\nAnd we would want the heroes `Black Lion` and `Princess Sure-E` to be **automatically deleted** too.\n\nSo we would end up with these teams and heroes:\n\n```mermaid\nflowchart TB\n    subgraph zforce[\"Team Z-Force\"]\n        d(\"Deadpond\")\n    end\n    subgraph preventers[\"Team Preventers\"]\n        r(\"Rusty-Man\")\n        s(\"Spider-Boy\")\n    end\n```\n\n## Configure Automatic Deletion\n\nThere are **two places** where this automatic deletion is configured:\n\n* in **Python code**\n* in the **database**\n\n## Delete in Python with `cascade_delete`\n\nWhen creating a `Relationship()`, we can set `cascade_delete=True`.\n\nThis configures SQLModel to **automatically delete** the related records (heroes) **when the initial one is deleted** (a team).\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial001_py310.py ln[1:9] hl[9] *}\n\nWith this configuration, when we delete a team, SQLModel (actually SQLAlchemy) will:\n\n* Make sure the objects for the **related records are loaded**, in this case, the `heroes`. If they are not loaded, it will send a `SELECT` query to the database to get them.\n* Send a `DELETE` query to the database **including each related record** (each hero).\n* Finally, **delete the initial record** (the team) with another `DELETE` query.\n\nThis way, the internal **Python code** will take care of deleting the related records, by emitting the necessary SQL queries for each of them.\n\n/// tip\n\nThe `cascade_delete` parameter is set in the `Relationship()`, on the model that **doesn't have a foreign key**.\n\n///\n\n/// note | Technical Details\n\nSetting `cascade_delete=True` in the `Relationship()` will configure SQLAlchemy to use `cascade=\"all, delete-orphan\"`, which is the most common and useful configuration when wanting to cascade deletes.\n\nYou can read more about it in the <a href=\"https://docs.sqlalchemy.org/en/20/orm/cascades.html\" class=\"external-link\" target=\"_blank\">SQLAlchemy docs</a>.\n\n///\n\n## Delete in the Database with `ondelete`\n\nIn the previous section we saw that using `cascade_delete` handles automatic deletions from the Python code.\n\nBut what happens if someone **interacts with the database directly**, not using our code, and **deletes a team with SQL**?\n\nFor those cases, we can configure the database to **automatically delete** the related records with the `ondelete` parameter in `Field()`.\n\n### `ondelete` Options\n\nThe `ondelete` parameter will set a SQL `ON DELETE` in the **foreign key column** in the database.\n\n`ondelete` can have these values:\n\n* `CASCADE`: **Automatically delete this record** (hero) when the related one (team) is deleted.\n* `SET NULL`: Set this **foreign key** (`hero.team_id`) field to `NULL` when the related record is deleted.\n* `RESTRICT`: **Prevent** the deletion of this record (hero) if there is a foreign key value by raising an error.\n\n## Set `ondelete` to `CASCADE`\n\nIf we want to configure the database to **automatically delete** the related records when the parent is deleted, we can set `ondelete=\"CASCADE\"`.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial001_py310.py ln[1:19] hl[18] *}\n\nNow, when we **create the tables** in the database, the `team_id` column in the `Hero` table will have an `ON DELETE CASCADE` in its definition at the database level.\n\nThis will **configure the database** to **automatically delete** the records (heroes) when the related record (team) is deleted.\n\n/// tip\n\nThe `ondelete` parameter is set in the `Field()`, on the model that **has a foreign key**.\n\n///\n\n## Using `cascade_delete` or `ondelete`\n\nAt this point, you might be wondering if you should use `cascade_delete` or `ondelete`. The answer is: **both**! 🤓\n\nThe `ondelete` will **configure the database**, in case someone interacts with it directly.\n\nBut `cascade_delete` is still needed to tell SQLAlchemy that it should delete the **Python objects** in memory.\n\n### Foreign Key Constraint Support\n\nSome databases don't support foreign key constraints.\n\nFor example, **SQLite** doesn't support them by default. They have to be manually enabled with a custom SQL command:\n\n```\nPRAGMA foreign_keys = ON;\n```\n\nSo, in general it's a good idea to have both `cascade_delete` and `ondelete` configured.\n\n/// tip\n\nYou will learn more about how to **disable the default** automatic SQLModel (SQLAlchemy) behavior and **only rely on the database** down below, in the section about `passive_deletes`.\n\n///\n\n### `cascade_delete` on `Relationship()` and `ondelete` on `Field()`\n\nJust a note to remember... 🤓\n\n* `ondelete` is put on the `Field()` with a **foreign key**. On the **\"many\"** side in \"one-to-many\" relationships.\n\n```Python\nclass Hero(SQLModel, table=True):\n    ...\n\n    team_id: int = Field(foreign_key=\"team.id\", ondelete=\"CASCADE\")\n```\n\n* `cascade_delete` is put on the `Relationship()`. Normally on the **\"one\"** side in \"one-to-many\" relationships, the side **without a foreign key**.\n\n```Python\nclass Team(SQLModel, table=True):\n    ...\n\n    heroes: list[Hero] = Relationship(cascade_delete=True)\n```\n\n## Remove a Team and its Heroes\n\nNow, when we **delete a team**, we don't need to do anything else, it's **automatically** going to **delete its heroes**.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial001_py310.py ln[76:82] hl[80] *}\n\n## Confirm Heroes are Deleted\n\nWe can confirm that **after deleting the team** `Wakaland`, the heroes `Black Lion` and `Princess Sure-E` are **also deleted**.\n\nIf we try to select them from the database, we will **no longer find them**.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial001_py310.py ln[85:95] hl[87,90,92,95] *}\n\n## Run the Program with `cascade_delete=True` and `ondelete=\"CASCADE\"`\n\nWe can confirm everything is working by running the program.\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The team table is created as before\nCREATE TABLE team (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        headquarters VARCHAR NOT NULL,\n        PRIMARY KEY (id)\n)\n\n// The hero table is created with the ON DELETE CASCADE 🎉\n// In SQLite, it also includes REFERENCES team (id), this is needed by SQLite to work with the ON DELETE CASCADE properly.\n// SQLAlchemy takes care of setting it up for us to make sure it works 🤓\nCREATE TABLE hero (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id) ON DELETE CASCADE\n)\n\n// We select the team Wakaland\nINFO Engine SELECT team.id, team.name, team.headquarters\nFROM team\nWHERE team.name = ?\nINFO Engine [generated in 0.00014s] ('Wakaland',)\n\n// Then, because of cascade_delete, right before deleting Wakaland, SQLAlchemy loads the heroes\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id\nFROM hero\nWHERE ? = hero.team_id\nINFO Engine [generated in 0.00020s] (3,)\n\n// Next, before deleting the Wakaland team, it sends a DELETE statement including each related hero: Black Lion and Princess Sure-E, with IDs 4 and 5\nINFO Engine DELETE FROM hero WHERE hero.id = ?\nINFO Engine [generated in 0.00022s] [(4,), (5,)]\n\n// After that, it will send the delete for the team Wakaland with ID 3\nINFO Engine DELETE FROM team WHERE team.id = ?\nINFO Engine [generated in 0.00017s] (3,)\n\n// Print the deleted team\nDeleted team: name='Wakaland' id=3 headquarters='Wakaland Capital City'\n\n// Finally, we try to select the heroes from Wakaland, Black Lion and Princess Sure-E and print them, but they are now deleted\nBlack Lion not found: None\nPrincess Sure-E not found: None\n```\n\n</div>\n\n## `ondelete` with `SET NULL`\n\nWe can configure the database to **set the foreign key** (the `team_id` in the `hero` table) to **`NULL`** when the related record (in the `team` table) is deleted.\n\nIn this case, the side with `Relationship()` won't have `cascade_delete`, but the side with `Field()` and a `foreign_key` will have `ondelete=\"SET NULL\"`.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial002_py310.py ln[1:21] hl[19] *}\n\nThe configuration above is setting the `team_id` column from the `Hero` table to have an `ON DELETE SET NULL`.\n\nThis way, when someone deletes a team from the database using SQL directly, the database will go to the heroes for that team and set `team_id` to `NULL` (if the database supports it).\n\n/// tip\n\nThe foreign key should allow `None` values (`NULL` in the database), otherwise you would end up having an Integrity Error by violating the `NOT NULL` constraint.\n\nSo `team_id` needs to have a type with `None`, like:\n\n```Python\nteam_id: int | None\n```\n\n///\n\n### Not Using `ondelete=\"SET NULL\"`\n\nWhat happens if you don't use `ondelete=\"SET NULL\"`, don't set anything on `cascade_delete`, and delete a team?\n\nThe default behavior is that SQLModel (actually SQLAlchemy) will go to the heroes and set their `team_id` to `NULL` from the **Python code**.\n\nSo, **by default**, those `team_id` fields will be **set to `NULL`**.\n\nBut if someone goes to the database and **manually deletes a team**, the heroes could end up with a `team_id` pointing to a non-existing team.\n\nAdding the `ondelete=\"SET NULL\"` configures the database itself to also set those fields to `NULL`.\n\nBut if you delete a team from code, by default, SQLModel (actually SQLAlchemy) will update those `team_id` fields to `NULL` even before the database `SET NULL` takes effect.\n\n### Removing a Team with `SET NULL`\n\nRemoving a team has the **same code** as before, the only thing that changes is the configuration underneath in the database.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial002_py310.py ln[78:84] hl[82] *}\n\nThe result would be these tables.\n\n#### Team Table after `SET NULL`\n\n| id   | name       | headquarters          |\n| ---- | ---------- | --------------------- |\n| 1    | Z-Force    | Sister Margaret's Bar |\n| 2    | Preventers | Sharp Tower           |\n\n#### Hero Table after `SET NULL`\n\n| id   | name            | secret_name      | age  | team_id |\n| ---- | --------------- | ---------------- | ---- | ------- |\n| 1    | Deadpond        | Dive Wilson      |      | 1       |\n| 2    | Rusty-Man       | Tommy Sharp      | 48   | 2       |\n| 3    | Spider-Boy      | Pedro Parqueador |      | 2       |\n| 4    | Black Lion      | Trevor Challa    | 35   | NULL    |\n| 5    | Princess Sure-E | Sure-E           |      | NULL    |\n\n#### Visual Teams and Heroes after `SET NULL`\n\nWe could visualize them like this:\n\n```mermaid\nflowchart TB\n    subgraph \"Z-Force\"\n        d(\"Deadpond\")\n    end\n    subgraph \"Preventers\"\n        r(\"Rusty-Man\")\n        s(\"Spider-Boy\")\n    end\n    b(\"Black Lion\")\n    p(\"Princess Sure-E\")\n```\n\n### Run the program with `SET NULL`\n\nLet's confirm it all works by running the program now:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The hero table is created with the ON DELETE SET NULL 🎉\n// In SQLite, it also includes: REFERENCES team (id). This REFERENCES is needed by SQLite to work with the ON DELETE CASCADE properly.\n// SQLModel with SQLAlchemy takes care of setting it up for us to make sure it works 🤓\nCREATE TABLE hero (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id) ON DELETE SET NULL\n)\n\n// We select the team Wakaland\nINFO Engine SELECT team.id, team.name, team.headquarters\nFROM team\nWHERE team.id = ?\nINFO Engine [generated in 0.00010s] (3,)\nTeam Wakaland: id=3 name='Wakaland' headquarters='Wakaland Capital City'\n\n// Then, right before deleting Wakaland, the heroes are loaded automatically\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id\nFROM hero\nWHERE ? = hero.team_id\nINFO Engine [generated in 0.00020s] (3,)\n\n// Next, before deleting the Wakaland team, it sends an UPDATE statement including each related hero: Black Lion and Princess Sure-E, with IDs 4 and 5, to set their team_id to NULL. This is not the SET NULL we added, this is just the default SQLModel (SQLAlchemy) behavior.\nINFO Engine UPDATE hero SET team_id=? WHERE hero.id = ?\nINFO Engine [generated in 0.00009s] [(None, 4), (None, 5)]\n\n// After that, it will send the delete for the team Wakaland with ID 3\nINFO Engine DELETE FROM team WHERE team.id = ?\nINFO Engine [generated in 0.00017s] (3,)\n\n// Print the deleted team\nDeleted team: name='Wakaland' id=3 headquarters='Wakaland Capital City'\n\n// Finally, we select the heroes Black Lion and Princess Sure-E and print them, they no longer have a team\nBlack Lion has no team: age=35 id=4 name='Black Lion' secret_name='Trevor Challa' team_id=None\nPrincess Sure-E has no team: age=None id=5 name='Princess Sure-E' secret_name='Sure-E' team_id=None\n```\n\n</div>\n\nThe team `Wakaland` was deleted and all of its heroes were left without a team, or in other words, with their `team_id` set to `NULL`, but still kept in the database! 🤓\n\n## Let the Database Handle it with `passive_deletes`\n\nIn the previous examples we configured `ondelete` with `CASCADE` and `SET NULL` to configure the database to handle the deletion of related records automatically. But we actually **never used that functionality** ourselves, because SQLModel (SQLAlchemy) **by default loads** the related records and **deletes** them or updates them with **NULL** before sending the `DELETE` for the team.\n\nIf you know your database would be able to correctly handle the deletes or updates on its own, just with `ondelete=\"CASCADE\"` or `ondelete=\"SET NULL\"`, you can use `passive_deletes=\"all\"` in the `Relationship()` to tell SQLModel (actually SQLAlchemy) to **not delete or update** those records (for heroes) before sending the `DELETE` for the team.\n\n### Enable Foreign Key Support in SQLite\n\nTo be able to test this out with SQLite, we first need to enable foreign key support.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial003_py310.py ln[30:33] hl[33] *}\n\n/// info\n\nYou can learn more about SQLite, foreign keys, and this SQL command on the <a href=\"https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#foreign-key-support\" class=\"external-link\" target=\"_blank\">SQLAlchemy docs</a>.\n\n///\n\n### Use `passive_deletes=\"all\"`\n\nNow let's update the table model for `Team` to use `passive_deletes=\"all\"` in the `Relationship()` for heroes.\n\nWe will also use `ondelete=\"SET NULL\"` in the `Hero` model table, in the foreign key `Field()` for the `team_id` to make the database set those fields to `NULL` automatically.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial003_py310.py ln[1:21] hl[9,19] *}\n\n### Run the Program with `passive_deletes`\n\nNow, if we run the program, we will see that SQLModel (SQLAlchemy) is no longer loading and updating the heroes, it just sends the `DELETE` for the team.\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The hero table is created with the ON DELETE SET NULL as before\nCREATE TABLE hero (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id) ON DELETE SET NULL\n)\n\n// For SQLite, we also send the custom command to enable foreign key support\nINFO Engine PRAGMA foreign_keys=ON\n\n// We select and print the team Wakaland\nTeam Wakaland: id=3 name='Wakaland' headquarters='Wakaland Capital City'\n\n// We won't see another SELECT for the heroes, nor an UPDATE or DELETE. SQLModel (with SQLAlchemy) won't try to load and update (or delete) the related records for heroes, it will just send the DELETE for the team right away.\nINFO Engine DELETE FROM team WHERE team.id = ?\nINFO Engine [generated in 0.00013s] (3,)\n\n// At this point, because we enabled foreign key support for SQLite, the database will take care of updating the records for heroes automatically, setting their team_id to NULL\n\n// Print the deleted team\nDeleted team: name='Wakaland' id=3 headquarters='Wakaland Capital City'\n\n// Finally, we select the heroes Black Lion and Princess Sure-E and print them, they no longer have a team\nBlack Lion has no team: age=35 id=4 name='Black Lion' secret_name='Trevor Challa' team_id=None\nPrincess Sure-E has no team: age=None id=5 name='Princess Sure-E' secret_name='Sure-E' team_id=None\n```\n\n</div>\n\n## `ondelete` with `RESTRICT`\n\nWe can also configure the database to **prevent the deletion** of a record (a team) if there are related records (heroes).\n\nIn this case, when someone attempts to **delete a team with heroes** in it, the database will **raise an error**.\n\nAnd because this is configured in the database, it will happen even if someone **interacts with the database directly using SQL** (if the database supports it).\n\n/// tip\n\nFor SQLite, this also needs enabling foreign key support.\n\n///\n\n### Enable Foreign Key Support in SQLite for `RESTRICT`\n\nAs `ondelete=\"RESTRICT\"` is mainly a database-level constraint, let's enable foreign key support in SQLite first to be able to test it.\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial004_py310.py ln[30:33] hl[33] *}\n\n### Use `ondelete=\"RESTRICT\"`\n\nLet's set `ondelete=\"RESTRICT\"` in the foreign key `Field()` for the `team_id` in the `Hero` model table.\n\nAnd in the `Team` model table, we will use `passive_deletes=\"all\"` in the `Relationship()` for heroes, this way the default behavior of setting foreign keys from deleted models to `NULL` will be disabled, and when we try to delete a team with heroes, the database will **raise an error**.\n\n/// tip\n\nNotice that we don't set `cascade_delete` in the `Team` model table.\n\n///\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial004_py310.py ln[1:21] hl[9,19] *}\n\n### Run the Program with `RESTRICT`, See the Error\n\nNow, if we run the program and try to delete a team with heroes, we will see an error.\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The hero table is created with the ON DELETE RESTRICT\nCREATE TABLE hero (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id) ON DELETE RESTRICT\n)\n\n// Now, when we reach the point of deleting a team with heroes, we will see an error\nTraceback (most recent call last):\n     File \"/home/user/code...\n\nsqlite3.IntegrityError: FOREIGN KEY constraint failed\n\n// More error output here...\n\nsqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) FOREIGN KEY constraint failed\n[SQL: DELETE FROM team WHERE team.id = ?]\n[parameters: (3,)]\n```\n\n</div>\n\nGreat! The database didn't let us commit the mistake of deleting a team with heroes. 🤓\n\n/// tip\n\nIf you want to test if the `PRAGMA foreign_keys=ON` is necessary, **comment that line** and run it again, you will **not see an error**. 😱\n\nThe same with `passive_deletes=\"all\"`, if you **comment that line**, SQLModel (SQLAlchemy) will load and update the heroes before deleting the team, set their foreign key `team_id` to `NULL` and **the constraint won't work as expected**, you will not see an error. 😅\n\n///\n\n### Update Heroes Before Deleting the Team\n\nAfter having the `ondelete=\"RESTRICT\"` in place, SQLite configured to support foreign keys, and `passive_deletes=\"all\"` in the `Relationship()`, if we try to delete a team with heroes, we will see an error.\n\nIf we want to delete the team, we need to **update the heroes first** and set their `team_id` to `None` (or `NULL` in the database).\n\nBy calling the method `.clear()` from a list, we remove all its items. So, by calling `team.heroes.clear()` and saving that to the database, we disassociate the heroes from the team, that will set their `team_id` to `None`.\n\n/// tip\n\nCalling `team.heroes.clear()` is very similar to what SQLModel (actually SQLAlchemy) would have done if we didn't have `passive_deletes=\"all\"` configured.\n\n///\n\n{* ./docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial005_py310.py ln[80:88] hl[84] *}\n\n### Run the Program Deleting Heroes First\n\nNow, if we run the program and delete the heroes first, we will be able to delete the team without any issues.\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The hero table is created with the ON DELETE RESTRICT\nCREATE TABLE hero (\n        id INTEGER NOT NULL,\n        name VARCHAR NOT NULL,\n        secret_name VARCHAR NOT NULL,\n        age INTEGER,\n        team_id INTEGER,\n        PRIMARY KEY (id),\n        FOREIGN KEY(team_id) REFERENCES team (id) ON DELETE RESTRICT\n)\n\n// We manually disassociate the heroes from the team\nINFO Engine UPDATE hero SET team_id=? WHERE hero.id = ?\nINFO Engine [generated in 0.00008s] [(None, 4), (None, 5)]\n\n// We print the team from which we removed heroes\nTeam with removed heroes: name='Wakaland' id=3 headquarters='Wakaland Capital City'\n\n// Now we can delete the team\nINFO Engine DELETE FROM team WHERE team.id = ?\nINFO Engine [generated in 0.00008s] (3,)\nINFO Engine COMMIT\nDeleted team: name='Wakaland' id=3 headquarters='Wakaland Capital City'\n\n// The heroes Black Lion and Princess Sure-E are no longer associated with the team\nBlack Lion has no team: secret_name='Trevor Challa' name='Black Lion' team_id=None age=35 id=4\nPrincess Sure-E has no team: secret_name='Sure-E' name='Princess Sure-E' team_id=None age=None id=5\n```\n\n</div>\n\n## Conclusion\n\nIn many cases, **you don't really need to configure anything**. 😎\n\nIn some cases, when you want to **cascade** the delete of a record to its related records automatically (delete a team with its heroes), you can:\n\n* Use `cascade_delete=True` in the `Relationship()` on the side **without a foreign key**\n* And use `ondelete=\"CASCADE\"` in the `Field()` with the **foreign key**\n\nThat will **cover most of the use cases**. 🚀\n\nAnd if you need something else, you can refer the additional options described above. 🤓\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/create-and-update-relationships.md",
    "content": "# Create and Update Relationships\n\nLet's see now how to create data with relationships using these new **relationship attributes**. ✨\n\n## Create Instances with Fields\n\nLet's check the old code we used to create some heroes and teams:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:58] hl[35,38,44,50] *}\n\nThere are several things to **notice** here.\n\nFirst, we **create** some `Team` instance objects. We want to use the IDs of these teams when creating the `Hero` instances, in the `team_id` field.\n\nBut model instances **don't have an ID** generated by the database until we `add` and `commit` them to the **session**. Before that, they are just `None`, and we want to use the actual IDs.\n\nSo, we have to `add` them and `commit` the session first, before we start creating the `Hero` instances, to be able to **use their IDs**.\n\nThen, we use those IDs when creating the `Hero` instances. We `add` the new heroes to the session, and then we `commit` them.\n\nSo, we are **committing twice**. And we have to remember to `add` some things first, and then `commit`, and do all that **in the right order**, otherwise we could end up using a `team.id` that is currently `None` because it hasn't been saved.\n\nThis is the first area where these **relationship attributes** can help. 🤓\n\n## Create Instances with Relationship Attributes\n\nNow let's do all that, but this time using the new, shiny `Relationship` attributes:\n\n{* ./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001_py310.py ln[32:55] hl[38,41,47] *}\n\nNow we can create the `Team` instances and pass them directly to the new `team` argument when creating the `Hero` instances, as `team=team_preventers` instead of `team_id=team_preventers.id`.\n\nAnd thanks to SQLAlchemy and how it works underneath, these teams don't even need to have an ID yet, but because we are assigning the whole object to each hero, those teams **will be automatically created** in the database, the automatic ID will be generated, and will be set in the `team_id` column for each of the corresponding hero rows.\n\nIn fact, now we don't even have to put the teams explicitly in the session with `session.add(team)`, because these `Team` instances are **already associated** with heroes that **we do** `add` to the session.\n\nSQLAlchemy knows that it also has to include those teams in the next commit to be able to save the heroes correctly.\n\nAnd then, as you can see, we only have to do one `commit()`.\n\n## Assign a Relationship\n\nThe same way we could assign an integer with a `team.id` to a `hero.team_id`, we can also assign the `Team` instance to the `hero.team`:\n\n{* ./docs_src/tutorial/relationship_attributes/create_and_update_relationships/tutorial001_py310.py ln[32:33,57:61] hl[57] *}\n\n## Create a Team with Heroes\n\nBefore, we created some `Team` instances and passed them in the `team=` argument when creating `Hero` instances.\n\nWe could also create the `Hero` instances first, and then pass them in the `heroes=` argument that takes a list, when creating a `Team` instance:\n\n{* ./docs_src/tutorial/relationship_attributes/create_and_update_relationships/tutorial001_py310.py ln[32:33,63:73] hl[68,70:71] *}\n\nHere we create two heroes first, **Black Lion** and **Princess Sure-E**, and then we pass them in the `heroes` argument.\n\nNotice that, the same as before, we only have to `add` the `Team` instance to the session, and because the heroes are connected to it, they will be automatically saved too when we `commit`.\n\n## Include Relationship Objects in the Many Side\n\nWe said before that this is a **many-to-one** relationship, because there can be **many** heroes that belong to **one** team.\n\nWe can also connect data with these relationship attributes on the **many** side.\n\nAs the attribute `team.heroes` behaves like a list, we can simply append to it.\n\nLet's create some more heroes and add them to the `team_preventers.heroes` list attribute:\n\n{* ./docs_src/tutorial/relationship_attributes/create_and_update_relationships/tutorial001_py310.py ln[32:33,75:91] hl[81:85] *}\n\nThe attribute `team_preventers.heroes` behaves like a list. But it's a special type of list, because when we modify it adding heroes to it, **SQLModel** (actually SQLAlchemy) **keeps track of the necessary changes** to be done in the database.\n\nThen we `add()` the team to the session and `commit()` it.\n\nAnd in the same way as before, we don't even have to `add()` the independent heroes to the session, because they are **connected to the team**.\n\n## Recap\n\nWe can use common Python objects and attributes to create and update data connections with these **relationship attributes**. 😎\n\nNext we'll see how to use these relationship attributes to read connected data. 🤝\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/define-relationships-attributes.md",
    "content": "# Define Relationships Attributes\n\nNow we are finally in one of the most exciting parts of **SQLModel**.\n\nRelationship Attributes. ✨\n\nWe currently have a `team` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>headquarters</th>\n</tr>\n<tr>\n<td>1</td><td>Preventers</td><td>Sharp Tower</td>\n</tr>\n<tr>\n<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>\n</tr>\n</table>\n\nAnd a `hero` table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>\n</tr>\n<tr>\n<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>\n</tr>\n<tr>\n<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>\n</tr>\n</table>\n\nNow that you know how these tables work underneath and how the model classes represent them, it's time to add a little convenience that will make many operations in code simpler.\n\n## Declare Relationship Attributes\n\nUp to now, we have only used the `team_id` column to connect the tables when querying with `select()`:\n\n{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[1:16] hl[16] *}\n\nThis is a **plain field** like all the others, all representing a **column in the table**.\n\nBut now let's add a couple of new special attributes to these model classes, let's add `Relationship` attributes.\n\nFirst, import `Relationship` from `sqlmodel`:\n\n{* ./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001_py310.py ln[1] hl[1] *}\n\nNext, use that `Relationship` to declare a new attribute in the model classes:\n\n{* ./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001_py310.py ln[1:19] hl[9,19] *}\n\n## What Are These Relationship Attributes\n\nThese new attributes are not the same as fields, they **don't represent a column** directly in the database, and their value is not a singular value like an integer. Their value is the actual **entire object** that is related.\n\nSo, in the case of a `Hero` instance, if you call `hero.team`, you will get the entire `Team` instance object that this hero belongs to. ✨\n\nFor example, you could check if a `hero` belongs to any `team` (if `.team` is not `None`) and then print the team's `name`:\n\n```Python\nif hero.team:\n    print(hero.team.name)\n```\n\n## Relationship Attributes or `None`\n\nNotice that in the `Hero` class, the type annotation for `team` is `Team | None`.\n\nThis means that this attribute could be `None`, or it could be a full `Team` object.\n\nThis is because the related **`team_id` could also be `None`** (or `NULL` in the database).\n\nIf it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `int | None`, its `Field` would be `Field(foreign_key=\"team.id\")` instead of `Field(default=None, foreign_key=\"team.id\")` and the `team` attribute would be a `Team` instead of `Team | None`.\n\n## Relationship Attributes With Lists\n\nAnd in the `Team` class, the `heroes` attribute is annotated as a list of `Hero` objects, because that's what it will have.\n\n**SQLModel** (actually SQLAlchemy) is smart enough to know that the relationship is established by the `team_id`, as that's the foreign key that points from the `hero` table to the `team` table, so we don't have to specify that explicitly here.\n\n/// tip\n\nThere's a couple of things we'll check again in some of the next chapters, about the `list[\"Hero\"]` and the `back_populates`.\n\nBut for now, let's first see how to use these relationship attributes.\n\n///\n\n## Next Steps\n\nNow let's see some real examples of how to use these new **relationship attributes** in the next chapters. ✨\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/index.md",
    "content": "# Relationship Attributes - Intro\n\nIn the previous chapters we discussed how to manage databases with tables that have **relationships** by using fields (columns) with **foreign keys** pointing to other columns.\n\nAnd then we read the data together with `select()` and using `.where()` or `.join()` to connect it.\n\nNow we will see how to use **Relationship Attributes**, an extra feature of **SQLModel** (and SQLAlchemy), to work with the data in the database in a much more familiar way, and closer to normal Python code.\n\n/// info\n\nWhen I say \"**relationship**\" I mean the standard dictionary term, of data related to other data.\n\nI'm not using the term \"**relation**\" that is the technical, academical, SQL term for a single table.\n\n///\n\nAnd using those **relationship attributes** is where a tool like **SQLModel** really shines. ✨\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/read-relationships.md",
    "content": "# Read Relationships\n\nNow that we know how to connect data using **relationship Attributes**, let's see how to get and read the objects from a relationship.\n\n## Select a Hero\n\nFirst, add a function `select_heroes()` where we get a hero to start working with, and add that function to the `main()` function:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial001_py310.py ln[94:98,108:111] hl[94:98,111] *}\n\n## Select the Related Team - Old Way\n\nNow that we have a hero, we can get the team this hero belongs to.\n\nWith what we have learned **up to now**, we could use a `select()` statement, then execute it with `session.exec()`, and then get the `.first()` result, for example:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial001_py310.py ln[94:103] hl[100:103] *}\n\n## Get Relationship Team - New Way\n\nBut now that we have the **relationship attributes**, we can just access them, and **SQLModel** (actually SQLAlchemy) will go and fetch the corresponding data from the database, and make it available in the attribute. ✨\n\nSo, the highlighted block above, has the same results as the block below:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial001_py310.py ln[94:98,105] hl[105] *}\n\n/// tip\n\nThe automatic data fetching will work as long as the starting object (in this case the `Hero`) is associated with an **open** session.\n\nFor example, here, **inside** a `with` block with a `Session` object.\n\n///\n\n## Get a List of Relationship Objects\n\nAnd the same way, when we are working on the **many** side of the **one-to-many** relationship, we can get a list of the related objects just by accessing the relationship attribute:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial002_py310.py ln[94:100] hl[100] *}\n\nThat would print a list with all the heroes in the Preventers team:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Automatically fetch the heroes\nINFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id\nFROM hero\nWHERE ? = hero.team_id\nINFO Engine [cached since 0.8774s ago] (2,)\n\n// Print the list of Preventers\nPreventers heroes: [\n    Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),\n    Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2),\n    Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),\n    Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),\n    Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)\n]\n```\n\n</div>\n\n## Recap\n\nWith **relationship attributes** you can use the power of common Python objects to easily access related data from the database. 😎\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/remove-relationships.md",
    "content": "# Remove Relationships\n\nNow let's say that **Spider-Boy** tells **Rusty-Man** something like:\n\n> I don't feel so good Mr. Sharp\n\nAnd then for some reason needs to leave the **Preventers** for some years. 😭\n\nWe can remove the relationship by setting it to `None`, the same as with the `team_id`, it also works with the new relationship attribute `.team`:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial002_py310.py ln[103:114] hl[109] *}\n\nAnd of course, we should remember to add this `update_heroes()` function to `main()` so that it runs when we call this program from the command line:\n\n{* ./docs_src/tutorial/relationship_attributes/read_relationships/tutorial002_py310.py ln[117:121] hl[121] *}\n\n## Recap\n\nThis chapter was too short for a recap, wasn't it? 🤔\n\nAnyway, **relationship attributes** make it easy and intuitive to work with relationships stored in the database. 🎉\n"
  },
  {
    "path": "docs/tutorial/relationship-attributes/type-annotation-strings.md",
    "content": "## About the String in `list[\"Hero\"]`\n\nIn the first Relationship attribute, we declare it with `list[\"Hero\"]`, putting the `Hero` in quotes instead of just normally there:\n\n{* ./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001_py310.py ln[1:19] hl[9] *}\n\nWhat's that about? Can't we just write it normally as `list[Hero]`?\n\nBy that point, in that line in the code, the Python interpreter **doesn't know of any class `Hero`**, and if we put it just there, it would try to find it unsuccessfully, and then fail. 😭\n\nBut by putting it in quotes, in a string, the interpreter sees it as just a string with the text `\"Hero\"` inside.\n\nBut the editor and other tools can see that **the string is actually a type annotation inside**, and provide all the autocompletion, type checks, etc. 🎉\n\nAnd of course, **SQLModel** can also understand it in the string correctly. ✨\n\nThat is actually part of Python, it's the current official solution to handle it.\n\n/// info\n\nThere's a lot of work going on in Python itself to make that simpler and more intuitive, and find ways to make it possible to not wrap the class in a string.\n\n///\n"
  },
  {
    "path": "docs/tutorial/select.md",
    "content": "# Read Data - SELECT\n\nWe already have a database and a table with some data in it that looks more or less like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\nThings are getting more exciting! Let's now see how to read data from the database! 🤩\n\n## Continue From Previous Code\n\nLet's continue from the last code we used to create some data.\n\n{* ./docs_src/tutorial/insert/tutorial002_py310.py ln[0] *}\n\nWe are creating a **SQLModel** `Hero` class model and creating some records.\n\nWe will need the `Hero` model and the **engine**, but we will create a new session to query data in a new function.\n\n## Read Data with SQL\n\nBefore writing Python code let's do a quick review of how querying data with SQL looks like:\n\n```SQL\nSELECT id, name, secret_name, age\nFROM hero\n```\n\nIt means, more or less:\n\n> Hey SQL database 👋, please go and `SELECT` some data for me.\n>\n> I'll first tell you the columns I want:\n>\n> * `id`\n> * `name`\n> * `secret_name`\n> * `age`\n>\n> And I want you to get them `FROM` the table called `\"hero\"`.\n\nThen the database will go and get the data and return it to you in a table like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\nYou can try that out in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/select/image01.png\">\n\n/// warning\n\nHere we are getting all the rows.\n\nIf you have thousands of rows, that could be expensive to compute for the database.\n\nYou would normally want to filter the rows to receive only the ones you want. But we'll learn about that later in the next chapter.\n\n///\n\n### A SQL Shortcut\n\nIf we want to get all the columns like in this case above, in SQL there's a shortcut, instead of specifying each of the column names we could write a `*`:\n\n```SQL\nSELECT *\nFROM hero\n```\n\nThat would end up in the same result. Although we won't use that for **SQLModel**.\n\n### `SELECT` Fewer Columns\n\nWe can also `SELECT` fewer columns, for example:\n\n```SQL\nSELECT id, name\nFROM hero\n```\n\nHere we are only selecting the `id` and `name` columns.\n\nAnd it would result in a table like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td>\n</tr>\n</table>\n\nAnd here is something interesting to notice. SQL databases store their data in tables. And they also always communicate their results in **tables**.\n\n### `SELECT` Variants\n\nThe SQL language allows several **variations** in several places.\n\nOne of those variations is that in `SELECT` statements you can use the names of the columns directly, or you can prefix them with the name of the table and a dot.\n\nFor example, the same SQL code above could be written as:\n\n```SQL\nSELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\n```\n\nThis will be particularly important later when working with multiple tables at the same time that could have the same name for some columns.\n\nFor example `hero.id` and `team.id`, or `hero.name` and `team.name`.\n\nAnother variation is that most of the SQL keywords like `SELECT` can also be written in lowercase, like `select`.\n\n### Result Tables Don't Have to Exist\n\nThis is the interesting part. The tables returned by SQL databases **don't have to exist** in the database as independent tables. 🧙\n\nFor example, in our database, we only have one table that has all the columns, `id`, `name`, `secret_name`, `age`. And here we are getting a result table with fewer columns.\n\nOne of the main points of SQL is to be able to keep the data structured in different tables, without repeating data, etc, and then query the database in many ways and get many different tables as a result.\n\n## Read Data with **SQLModel**\n\nNow let's do the same query to read all the heroes, but with **SQLModel**.\n\n## Create a **Session**\n\nThe first step is to create a **Session**, the same way we did when creating the rows.\n\nWe will start with that in a new function `select_heroes()`:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[34:35] hl[34:35] *}\n\n## Create a `select` Statement\n\nNext, pretty much the same way we wrote a SQL `SELECT` statement above, now we'll create a **SQLModel** `select` statement.\n\nFirst we have to import `select` from `sqlmodel` at the top of the file:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[1] hl[1] *}\n\nAnd then we will use it to create a `SELECT` statement in Python code:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[1,34:36] hl[36] *}\n\nIt's a very simple line of code that conveys a lot of information:\n\n```Python\nstatement = select(Hero)\n```\n\nThis is equivalent to the first SQL `SELECT` statement above:\n\n```SQL\nSELECT id, name, secret_name, age\nFROM hero\n```\n\nWe pass the class model `Hero` to the `select()` function. And that tells it that we want to select all the columns necessary for the `Hero` class.\n\nAnd notice that in the `select()` function we don't explicitly specify the `FROM` part. It is already obvious to **SQLModel** (actually to SQLAlchemy) that we want to select `FROM` the table `hero`, because that's the one associated with the `Hero` class model.\n\n/// tip\n\nThe value of the `statement` returned by `select()` is a special object that allows us to do other things.\n\nI'll tell you about that in the next chapters.\n\n///\n\n## Execute the Statement\n\nNow that we have the `select` statement, we can execute it with the **session**:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[34:37] hl[37] *}\n\nThis will tell the **session** to go ahead and use the **engine** to execute that `SELECT` statement in the database and bring the results back.\n\nBecause we created the **engine** with `echo=True`, it will show the SQL it executes in the output.\n\nThis `session.exec(statement)` will generate this output:\n\n```\nINFO Engine BEGIN (implicit)\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nINFO Engine [no key 0.00032s] ()\n```\n\nThe database returns the table with all the data, just like above when we wrote SQL directly:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n## Iterate Through the Results\n\nThe `results` object is an <abbr title=\"Something that can be used in a for loop\">iterable</abbr> that can be used to go through each one of the rows.\n\nNow we can put it in a `for` loop and print each one of the heroes:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[34:39] hl[38:39] *}\n\nThis will print the output:\n\n```\nid=1 name='Deadpond' age=None secret_name='Dive Wilson'\nid=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador'\nid=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp'\n```\n\n## Add `select_heroes()` to `main()`\n\nNow include a call to `select_heroes()` in the `main()` function so that it is executed when we run the program from the command line:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[34:45] hl[45] *}\n\n## Review The Code\n\nGreat, you're now being able to read the data from the database! 🎉\n\nLet's review the code up to this point:\n\n//// tab | Python 3.10+\n\n```{ .python .annotate }\n{!./docs_src/tutorial/select/tutorial002_py310.py!}\n```\n\n{!./docs_src/tutorial/select/annotations/en/tutorial002.md!}\n\n////\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\nHere it starts to become more evident why we should have a single **engine** for the whole application, but different **sessions** for each group of operations.\n\nThis new session we created uses the *same* **engine**, but it's a new and independent **session**.\n\nThe code above creating the models could, for example, live in a function handling web API requests and creating models.\n\nAnd the second section reading data from the database could be in another function for other requests.\n\nSo, both sections could be in **different places** and would need their own sessions.\n\n/// info\n\nTo be fair, in this example all that code could actually share the same **session**, there's actually no need to have two here.\n\nBut it allows me to show you how they could be separated and to reinforce the idea that you should have **one engine** per application, and **multiple sessions**, one per each group of operations.\n\n///\n\n## Get a List of `Hero` Objects\n\nUp to now we are using the `results` to iterate over them.\n\nBut for different reasons you might want to have the full **list of `Hero`** objects right away instead of just an *iterable*. For example, if you want to return them in a web API.\n\nThe special `results` object also has a method `results.all()` that returns a list with all the objects:\n\n{* ./docs_src/tutorial/select/tutorial003_py310.py ln[34:39] hl[38] *}\n\nWith this now we have all the heroes in a list in the `heroes` variable.\n\nAfter printing it, we would see something like:\n\n```\n[\n    Hero(id=1, name='Deadpond', age=None, secret_name='Dive Wilson'),\n    Hero(id=2, name='Spider-Boy', age=None, secret_name='Pedro Parqueador'),\n    Hero(id=3, name='Rusty-Man', age=48, secret_name='Tommy Sharp')\n]\n```\n\n/// info\n\nIt would actually look more compact, I'm formatting it a bit for you to see that it is actually a list with all the data.\n\n///\n\n## Compact Version\n\nI have been creating several variables to be able to explain to you what each thing is doing.\n\nBut knowing what is each object and what it is all doing, we can simplify it a bit and put it in a more compact form:\n\n{* ./docs_src/tutorial/select/tutorial004_py310.py ln[34:37] hl[36] *}\n\nHere we are putting it all on a single line, you will probably put the select statements in a single line like this more often.\n\n## SQLModel or SQLAlchemy - Technical Details\n\n**SQLModel** is actually, more or less, just **SQLAlchemy** and **Pydantic** underneath, combined together.\n\nIt uses and returns the same types of objects and is compatible with both libraries.\n\nNevertheless, **SQLModel** defines a few of its own internal parts to improve the developer experience.\n\nIn this chapter we are touching some of them.\n\n### SQLModel's `select`\n\nWhen importing from `sqlmodel` the `select()` function, you are using **SQLModel**'s version of `select`.\n\nSQLAchemy also has its own `select`, and SQLModel's `select` uses SQLAlchemy's `select` internally.\n\nBut SQLModel's version does a lot of **tricks** with type annotations to make sure you get the best **editor support** possible, no matter if you use **VS Code**, **PyCharm**, or something else. ✨\n\n/// info\n\nThere was a lot of work and research, with different versions of the internal code, to improve this as much as possible. 🤓\n\n///\n\n### SQLModel's `session.exec`\n\n📢 This is one to pay special attention to.\n\nSQLAlchemy's own `Session` has a method `session.execute()`. It doesn't have a `session.exec()` method.\n\nIf you see SQLAlchemy tutorials, they will always use `session.execute()`.\n\n**SQLModel**'s own `Session` inherits directly from SQLAlchemy's `Session`, and adds this additional method `session.exec()`. Underneath, it uses the same `session.execute()`.\n\nBut `session.exec()` does several **tricks** combined with the tricks in `session()` to give you the **best editor support**, with **autocompletion** and **inline errors** everywhere, even after getting data from a select. ✨\n\nFor example, in SQLAlchemy you would need to add a `.scalars()` here:\n\n```Python\nheroes = session.execute(select(Hero)).scalars().all()\n```\n\nBut you would have to remove it when selecting multiple things (we'll see that later).\n\nSQLModel's `session.exec()` takes care of that for you, so you don't have to add the `.scalars()`.\n\nThis is something that SQLAlchemy currently can't provide, because the regular `session.execute()` supports several other use cases, including legacy ones, so it can't have all the internal type annotations and tricks to support this.\n\nOn top of that, **SQLModel**'s `session.exec()` also does some tricks to reduce the amount of code you have to write and to make it as intuitive as possible.\n\nBut SQLModel's `Session` still has access to `session.execute()` too.\n\n/// tip\n\nYour editor will give you autocompletion for both `session.exec()` and `session.execute()`.\n\n📢 Remember to **always use `session.exec()`** to get the best editor support and developer experience.\n\n///\n\n### Caveats of **SQLModel** Flavor\n\nSQLModel is designed to have the best **developer experience** in a narrow set of **very common use cases**. ✨\n\nYou can still combine it with SQLAlchemy directly and use **all the features** of SQLAlchemy when you need to, including lower level more \"pure\" SQL constructs, exotic patterns, and even legacy ones. 🤓\n\nBut **SQLModel**'s design (e.g. type annotations) assume you are using it in the ways I explain here in the documentation.\n\nThanks to this, you will get as much **autocompletion** and **inline errors** as possible. 🚀\n\nBut this also means that if you use SQLModel with some more **exotic patterns** from SQLAlchemy, your editor might tell you that *there's an error*, while in fact, the code would still work.\n\nThat's the trade-off. 🤷\n\nBut for the situations where you need those exotic patterns, you can always use SQLAlchemy directly combined with SQLModel (using the same models, etc).\n"
  },
  {
    "path": "docs/tutorial/update.md",
    "content": "# Update Data - UPDATE\n\nNow let's see how to update data using **SQLModel**.\n\n## Continue From Previous Code\n\nAs before, we'll continue from where we left off with the previous code.\n\n{* ./docs_src/tutorial/indexes/tutorial002_py310.py ln[0] *}\n\nRemember to remove the `database.db` file before running the examples to get the same results.\n\n## Update with SQL\n\nLet's quickly check how to update data with SQL:\n\n```SQL hl_lines=\"1-2\"\nUPDATE hero\nSET age=16\nWHERE name = \"Spider-Boy\"\n```\n\nThis means, more or less:\n\n> Hey SQL database 👋, I want to `UPDATE` the table called `hero`.\n>\n> Please `SET` the value of the `age` column to `16`...\n>\n> ...for each of the rows `WHERE` the value of the column `name` is equal to `\"Spider-Boy\"`.\n\nIn a similar way to `SELECT` statements, the first part defines the columns to work with: what are the columns that have to be updated and to which value. The rest of the columns stay as they were.\n\nAnd the second part, with the `WHERE`, defines to which rows it should apply that update.\n\nIn this case, as we only have one hero with the name `\"Spider-Boy\"`, it will only apply the update in that row.\n\n/// info\n\nNotice that in the `UPDATE` the single equals sign (`=`) means **assignment**, setting a column to some value.\n\nAnd in the `WHERE` the same single equals sign (`=`) is used for **comparison** between two values, to find rows that match.\n\nThis is in contrast to Python and most programming languages, where a single equals sign (`=`) is used for assignment, and two equal signs (`==`) are used for comparisons.\n\n///\n\nYou can try that in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/update/image01.png\">\n\nAfter that update, the data in the table will look like this, with the new age for Spider-Boy:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>16 ✨</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n/// tip\n\nIt will probably be more common to find the row to update by `id`, for example:\n\n```SQL\nUPDATE hero\nSET age=16\nWHERE id = 2\n```\n\nBut in the example above I used `name` to make it more intuitive.\n\n///\n\nNow let's do the same update in code, with **SQLModel**.\n\nTo get the same results, delete the `database.db` file before running the examples.\n\n## Read From the Database\n\nWe'll start by selecting the hero `\"Spider-Boy\"`, this is the one we will update:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:47] hl[44] *}\n\nLet's not forget to add that `update_heroes()` function to the `main()` function so that we call it when executing the program from the command line:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[56:63] hl[59] *}\n\nUp to that point, running that in the command line will output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate and previous output omitted 😉\n\n// The SELECT with WHERE\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00017s] ('Spider-Boy',)\n\n// Print the hero as obtained from the database\nHero: name='Spider-Boy' secret_name='Pedro Parqueador' age=None id=2\n```\n\n</div>\n\n/// tip\n\nNotice that by this point, the hero still doesn't have an age.\n\n///\n\n## Set a Field Value\n\nNow that you have a `hero` object, you can simply set the value of the field (the attribute representing a column) that you want.\n\nIn this case, we will set the `age` to `16`:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:49] hl[49] *}\n\n## Add the Hero to the Session\n\nNow that the hero object in memory has a change, in this case a new value for the `age`, we need to add it to the session.\n\nThis is the same we did when creating new hero instances:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:50] hl[50] *}\n\n## Commit the Session\n\nTo save the current changes in the session, **commit** it.\n\nThis will save the updated hero in the database:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:51] hl[51] *}\n\nIt will also save anything else that was added to the session.\n\nFor example, if you were also creating new heroes and had added those objects to the session before, they would now be saved too in this single commit.\n\nThis commit will generate this output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// The SQL to update the hero in the database\nINFO Engine UPDATE hero SET age=? WHERE hero.id = ?\nINFO Engine [generated in 0.00017s] (16, 2)\nINFO Engine COMMIT\n```\n\n</div>\n\n## Refresh the Object\n\nAt this point, the hero is updated in the database and it has the new data saved there.\n\nThe data in the object would be automatically refreshed if we accessed an attribute, like `hero.name`.\n\nBut in this example we are not accessing any attribute, we will only print the object. And we also want to be explicit, so we will `.refresh()` the object directly:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:52] hl[52] *}\n\nThis refresh will trigger the same SQL query that would be automatically triggered by accessing an attribute. So it will generate this output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// The SQL to SELECT the fresh hero data\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.id = ?\nINFO Engine [generated in 0.00018s] (2,)\n```\n\n</div>\n\n## Print the Updated Object\n\nNow we can just print the hero:\n\n{* ./docs_src/tutorial/update/tutorial001_py310.py ln[42:53] hl[53] *}\n\nBecause we refreshed it right after updating it, it has fresh data, including the new `age` we just updated.\n\nSo, printing it will show the new `age`:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Previous output omitted 🙈\n\n// Print the hero with the new age\nUpdated hero: name='Spider-Boy' secret_name='Pedro Parqueador' age=16 id=2\n```\n\n</div>\n\n## Review the Code\n\nNow let's review all that code:\n\n//// tab | Python 3.10+\n\n```{ .python .annotate hl_lines=\"42-53\" }\n{!./docs_src/tutorial/update/tutorial002_py310.py!}\n```\n\n{!./docs_src/tutorial/update/annotations/en/tutorial002.md!}\n\n////\n\n/// tip\n\nCheck out the number bubbles to see what is done by each line of code.\n\n///\n\n## Multiple Updates\n\nThe update process with **SQLModel** is more or less the same as with creating new objects, you add them to the session, and then commit them.\n\nThis also means that you can update several fields (attributes, columns) at once, and you can also update several objects (heroes) at once:\n\n//// tab | Python 3.10+\n\n```{ .python .annotate hl_lines=\"15-17  19-21  23\" }\n# Code above omitted 👆\n\n{!./docs_src/tutorial/update/tutorial004_py310.py[ln:42-68]!}\n\n# Code below omitted 👇\n```\n\n{!./docs_src/tutorial/update/annotations/en/tutorial004.md!}\n\n////\n\n/// details | 👀 Full file preview\n\n//// tab | Python 3.10+\n\n```Python\n{!./docs_src/tutorial/update/tutorial004_py310.py!}\n```\n\n////\n\n///\n\n/// tip\n\nReview what each line does by clicking each number bubble in the code. 👆\n\n///\n\n## Recap\n\nUpdate **SQLModel** objects just as you would with other Python objects. 🐍\n\nJust remember to `add` them to a **session**, and then `commit` it. And if necessary, `refresh` them.\n"
  },
  {
    "path": "docs/tutorial/where.md",
    "content": "# Filter Data - WHERE\n\nIn the previous chapter we saw how to `SELECT` data from the database.\n\nWe did it using pure **SQL** and using **SQLModel**.\n\nBut we always got all the rows, the whole table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\nIn most of the cases we will want to get only one row, or only a group of rows.\n\nWe will see how to do that now, to filter data and get only the rows **where** a condition is true.\n\n## Continue From Previous Code\n\nWe'll continue with the same examples we have been using in the previous chapters to create and select data.\n\nAnd now we will update `select_heroes()` to filter the data.\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[0] *}\n\nIf you already executed the previous examples and have a database with data, **remove the database file** before running each example, that way you won't have duplicate data and you will be able to get the same results.\n\n## Filter Data with SQL\n\nLet's check first how to filter data with **SQL** using the `WHERE` keyword.\n\n```SQL hl_lines=\"3\"\nSELECT id, name, secret_name, age\nFROM hero\nWHERE name = \"Deadpond\"\n```\n\nThe first part means the same as before:\n\n> Hey SQL database 👋, please go and `SELECT` some data for me.\n>\n> I'll first tell you the columns I want:\n>\n> * `id`\n> * `name`\n> * `secret_name`\n> * `age`\n>\n> And I want you to get them `FROM` the table called `\"hero\"`.\n\nThen the `WHERE` keyword adds the following:\n\n> So, SQL database, I already told you what columns to `SELECT` and where to select them `FROM`.\n> But I don't want you to bring me all the rows, I only want the rows `WHERE` the `name` column has a value of `\"Deadpond\"`.\n\nThen the database will bring a table like this:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n</table>\n\n/// tip\n\nEven if the result is only one row, the database always returns a **table**.\n\nIn this case, a table with only one row.\n\n///\n\nYou can try that out in **DB Browser for SQLite**:\n\n<img class=\"shadow\" src=\"/img/tutorial/where/image01.png\">\n\n### `WHERE` and `FROM` are \"clauses\"\n\nThese additional keywords with some sections like `WHERE` and `FROM` that go after `SELECT` (or others) have a technical name, they are called **clauses**.\n\nThere are others clauses too, with their own SQL keywords.\n\nI won't use the term **clause** too much here, but it's good for you to know it as it will probably show up in other tutorials you could study later. 🤓\n\n## `SELECT` and `WHERE`\n\nHere's a quick tip that helps me think about it.\n\n* **`SELECT`** is used to tell the SQL database what **columns** to return.\n* **`WHERE`** is used to tell the SQL database what **rows** to return.\n\nThe size of the table in the two dimensions depend mostly on those two keywords.\n\n### `SELECT` Land\n\nIf the table has too many or too few **columns**, that's changed in the **`SELECT`** part.\n\nStarting with some table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n...and changing the number of **columns**:\n\n<table>\n<tr>\n<th>name</th>\n</tr>\n<tr>\n<td>Deadpond</td>\n</tr>\n<tr>\n<td>Spider-Boy</td>\n</tr>\n<tr>\n<td>Rusty-Man</td>\n</tr>\n</table>\n\n...is all `SELECT` land.\n\n### `WHERE` Land\n\nIf the table has too many or too few **rows**, that's changed in the **`WHERE`** part.\n\nStarting with some table:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n<tr>\n<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td>\n</tr>\n</table>\n\n...and changing the number of **rows**:\n\n<table>\n<tr>\n<th>id</th><th>name</th><th>secret_name</th><th>age</th>\n</tr>\n<tr>\n<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td>\n</tr>\n</table>\n\n...is all `WHERE` land.\n\n## Review `SELECT` with **SQLModel**\n\nLet's review some of the code we used to read data with **SQLModel**.\n\nWe care specially about the **select** statement:\n\n{* ./docs_src/tutorial/select/tutorial001_py310.py ln[34:39] hl[36] *}\n\n## Filter Rows Using `WHERE` with **SQLModel**\n\nNow, the same way that we add `WHERE` to a SQL statement to filter rows, we can add a `.where()` to a **SQLModel** `select()` statement to filter rows, which will filter the objects returned:\n\n{* ./docs_src/tutorial/where/tutorial001_py310.py ln[34:39] hl[36] *}\n\nIt's a very small change, but it's packed of details. Let's explore them.\n\n## `select()` Objects\n\nThe object returned by `select(Hero)` is a special type of object with some methods.\n\nOne of those methods is `.where()` used to (unsurprisingly) add a `WHERE` to the SQL statement in that **select** object.\n\nThere are other methods that we will explore later. 💡\n\nMost of these methods return the same object again after modifying it.\n\nSo we could call one after the other:\n\n```Python\nstatement = select(Hero).where(Hero.name == \"Deadpond\").where(Hero.age == 48)\n```\n\n## Calling `.where()`\n\nNow, this `.where()` method is special and very powerful. It is tightly integrated with **SQLModel** (actually SQLAlchemy) to let you use very familiar Python syntax and code.\n\nNotice that we didn't call it with a single equal (`=`) sign, and with something like:\n\n```Python\n# Not supported 🚨\nselect(Hero).where(name=\"Deadpond\")\n```\n\nThat would have been shorter, of course, but it would have been much more error prone and limited. I'll show you why in a bit.\n\nInstead, we used two `==`:\n\n```Python\nselect(Hero).where(Hero.name == \"Deadpond\")\n```\n\nSo, what's happening there?\n\n## `.where()` and Expressions\n\nIn the example above we are using two equal signs (`==`). That's called the \"**equality operator**\".\n\n/// tip\n\nAn **operator** is just a symbol that is put beside one value or in the middle of two values to do something with them.\n\n`==` is called the **equality** operator because it checks if two things are **equal**.\n\n///\n\nWhen writing Python, if you write something using this equality operator (`==`) like:\n\n```Python\nsome_name == \"Deadpond\"\n```\n\n...that's called an equality \"**comparison**\", and it normally results in a value of:\n\n```Python\nTrue\n```\n\n...or\n\n```Python\nFalse\n```\n\n/// tip\n\n`<`, `>`, `==`, `>=`, `<=`, and `!=` are all **operators** used for **comparisons**.\n\n///\n\nBut SQLAlchemy adds some magic to the columns/fields in a **model class** to make those Python comparisons have super powers.\n\nSo, if you write something like:\n\n```Python\nHero.name == \"Deadpond\"\n```\n\n...that doesn't result in a value of `True` or `False`. 🤯\n\nInstead, it results in a special type of object. If you tried that in an interactive Python session, you'd see something like:\n\n```Python\n>>> Hero.name == \"Deadpond\"\n<sqlalchemy.sql.elements.BinaryExpression object at 0x7f4aec0d6c90>\n```\n\nSo, that result value is an **expression** object. 💡\n\nAnd `.where()` takes one (or more) of these **expression** objects to update the SQL statement.\n\n## Model Class Attributes, Expressions, and Instances\n\nNow, let's stop for a second to make a clear distinction that is very important and easy to miss.\n\n**Model class attributes** for each of the columns/fields are special and can be used for expressions.\n\nBut that's only for the **model class attributes**. 🚨\n\n**Instance** attributes behave like normal Python values. ✅\n\nSo, using the class (`Hero`, with capital `H`) in a Python comparison:\n\n```Python\nHero.name == \"Deadpond\"\n```\n\n...results in one of those **expression** objects to be used with `.where()`:\n\n```Python\n<sqlalchemy.sql.elements.BinaryExpression object at 0x7f4aec0d6c90>\n```\n\nBut if you take an instance:\n\n```Python\nsome_hero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n```\n\n...and use it in a comparison:\n\n```Python\nsome_hero.name == \"Deadpond\"\n```\n\n...that results in a Python value of:\n\n```Python\nTrue\n```\n\n...or if it was a different object with a different name, it could have been:\n\n```Python\nFalse\n```\n\nThe difference is that one is using the **model class**, the other is using an **instance**.\n\n## Class or Instance\n\nIt's quite probable that you will end up having some variable `hero` (with lowercase `h`) like:\n\n```Python\nhero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n```\n\nAnd now the class is `Hero` (with capital `H`) and the instance is `hero` (with a lowercase `h`).\n\nSo now you have `Hero.name` and `hero.name` that look very similar, but are two different things:\n\n```Python\n>>> Hero.name == \"Deadpond\"\n<sqlalchemy.sql.elements.BinaryExpression object at 0x7f4aec0d6c90>\n\n>>> hero.name == \"Deadpond\"\nTrue\n```\n\nIt's just something to pay attention to. 🤓\n\nBut after understanding that difference between classes and instances it can feel natural, and you can do very powerful things. 🚀\n\nFor example, as `hero.name` works like a `str` and `Hero.name` works like a special object for comparisons, you could write some code like:\n\n```Python\nselect(Hero).where(Hero.name == hero.name)\n```\n\nThat would mean:\n\n> Hey SQL Database 👋, please `SELECT` all the columns\n>\n> `FROM` the table for the model class `Hero` (the table `\"hero\"`)\n>\n> `WHERE` the column `\"name\"` is equal to the name of this hero instance I have here: `hero.name` (in the example above, the value `\"Deadpond\"`).\n\n## `.where()` and Expressions Instead of Keyword Arguments\n\nNow, let me tell you why I think that for this use case of interacting with SQL databases it's better to have these expressions:\n\n```Python\n# Expression ✨\nselect(Hero).where(Hero.name == \"Deadpond\")\n```\n\n...instead of keyword arguments like this:\n\n```Python\n# Not supported, keyword argument 🚨\nselect(Hero).where(name=\"Deadpond\")\n```\n\nOf course, the keyword arguments would have been a bit shorter.\n\nBut with the **expressions** your editor can help you a lot with autocompletion and inline error checks. ✨\n\nLet me give you an example. Let's imagine that keyword arguments were supported in SQLModel and you wanted to filter using the secret identity of Spider-Boy.\n\nYou could write:\n\n```Python\n# Don't copy this 🚨\nselect(Hero).where(secret_identity=\"Pedro Parqueador\")\n```\n\nThe editor would see the code, and because it doesn't have any information of which keyword arguments are allowed and which not, it would have no way to help you **detect the error**.\n\nMaybe your code could even run and seem like it's all fine, and then some months later you would be wondering why your app *never finds rows* although you were sure that there was one `\"Pedro Parqueador\"`. 😱\n\nAnd maybe finally you would realize that we wrote the code using `secret_identity` which is not a column in the table. We should have written `secret_name` instead.\n\nNow, with the expressions, your editor would show you an error right away if you tried this:\n\n```Python\n# Expression ✨\nselect(Hero).where(Hero.secret_identity == \"Pedro Parqueador\")\n```\n\nEven better, it would autocomplete the correct one for you, to get:\n\n```Python\nselect(Hero).where(Hero.secret_name == \"Pedro Parqueador\")\n```\n\nI think that alone, having better editor support, autocompletion, and inline errors, is enough to make it worth having expressions instead of keyword arguments. ✨\n\n/// tip\n\n**Expressions** also provide more features for other types of comparisons, shown down below. 👇\n\n///\n\n## Exec the Statement\n\nNow that we know how `.where()` works, let's finish the code.\n\nIt's actually the same as in previous chapters for selecting data:\n\n{* ./docs_src/tutorial/where/tutorial001_py310.py ln[34:39] hl[37:39] *}\n\nWe take that statement, that now includes a `WHERE`, and we `exec()` it to get the results.\n\nAnd in this case the results will be just one:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// Now the important part, the SELECT with WHERE 💡\n\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.name = ?\nINFO Engine [no key 0.00014s] ('Deadpond',)\n\n// Here's the only printed hero\nsecret_name='Dive Wilson' age=None id=1 name='Deadpond'\n```\n\n</div>\n\n\n/// tip\n\nThe `results` object is an iterable to be used in a `for` loop.\n\nEven if we got only one row, we iterate over that `results` object. Just as if it was a list of one element.\n\nWe'll see other ways to get the data later.\n\n///\n\n## Other Comparisons\n\nHere's another great advantage of these special **expressions**  passed to `.where()`.\n\nAbove, we have been using an \"equality\" comparison (using `==`), only checking if two things are the same value.\n\nBut we can use other standard Python comparisons. ✨\n\n### Not Equal\n\nWe could get the rows where a column is **not** equal to a value using `!=`:\n\n{* ./docs_src/tutorial/where/tutorial002_py310.py ln[34:39] hl[36] *}\n\nThat would output:\n\n```\nsecret_name='Pedro Parqueador' age=None id=2 name='Spider-Boy'\nsecret_name='Tommy Sharp' age=48 id=3 name='Rusty-Man'\n```\n\n### Pause to Add Data\n\nLet's update the function `create_heroes()` and add some more rows to make the next comparison examples clearer:\n\n{* ./docs_src/tutorial/where/tutorial003_py310.py ln[21:39] hl[22:28,31:37] *}\n\nNow that we have several heroes with different ages, it's gonna be more obvious what the next comparisons do.\n\n### More Than\n\nNow let's use `>` to get the rows where a column is **more than** a value:\n\n{* ./docs_src/tutorial/where/tutorial003_py310.py ln[42:47] hl[44] *}\n\nThat would output:\n\n```\nage=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\nage=36 id=6 name='Dr. Weird' secret_name='Steve Weird'\nage=93 id=7 name='Captain North America' secret_name='Esteban Rogelios'\n```\n\n/// tip\n\nNotice that it didn't select `Black Lion`, because the age is not *strictly* greater than `35`.\n\n///\n\n### More Than or Equal\n\nLet's do that again, but with `>=` to get the rows where a column is **more than or equal** to a value:\n\n{* ./docs_src/tutorial/where/tutorial004_py310.py ln[42:47] hl[44] *}\n\nBecause we are using `>=`, the age `35` will be included in the output:\n\n``` hl_lines=\"2\"\nage=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\nage=35 id=5 name='Black Lion' secret_name='Trevor Challa'\nage=36 id=6 name='Dr. Weird' secret_name='Steve Weird'\nage=93 id=7 name='Captain North America' secret_name='Esteban Rogelios'\n```\n\n/// tip\n\nThis time we got `Black Lion` too because although the age is not *strictly* greater than `35`it is *equal* to `35`.\n\n///\n\n### Less Than\n\nSimilarly, we can use `<` to get the rows where a column is **less than** a value:\n\n{* ./docs_src/tutorial/where/tutorial005_py310.py ln[42:47] hl[44] *}\n\nAnd we get the younger one with an age in the database:\n\n```\nage=32 id=4 name='Tarantula' secret_name='Natalia Roman-on'\n```\n\n/// tip\n\nWe could imagine that **Spider-Boy** is even **younger**. But because we don't know the age, it is `NULL` in the database (`None` in Python), it doesn't match any of these age comparisons with numbers.\n\n///\n\n### Less Than or Equal\n\nWe can also use `<=` to get the rows where a column is **less than or equal** to a value:\n\n{* ./docs_src/tutorial/where/tutorial006_py310.py ln[42:47] hl[44] *}\n\nAnd we get the younger ones, `35` and below:\n\n``` hl_lines=\"2\"\nage=32 id=4 name='Tarantula' secret_name='Natalia Roman-on'\nage=35 id=5 name='Black Lion' secret_name='Trevor Challa'\n```\n\n/// tip\n\nWe get `Black Lion` here too because although the age is not *strictly* less than `35` it is *equal* to `35`.\n\n///\n\n### In\n\nFinally, we can use `in_` to get the rows where a column is a member of a collection of values:\n\n{* ./docs_src/tutorial/where/tutorial006b_py310.py ln[42:47] hl[44] *}\n\nIn this case, we match `Deadpond` since it's part of the collections of names.\nWe don't have any hero called `Ratman`, so it does not match any hero.\n\n/// tip\n\nYou need to wrap your attribute with `col()` to use `in_`.\nYou can read more about it in the [Type annotations and errors](#type-annotations-and-errors){.internal-link target=_blank} section.\n\n///\n\n### Benefits of Expressions\n\nHere's a good moment to see that being able to use these pure Python expressions instead of keyword arguments can help a lot. ✨\n\nWe can use the same standard Python comparison operators like `<`, `<=`, `>`, `>=`, `==`, etc.\n\n## Multiple `.where()`\n\nBecause `.where()` returns the same special select object back, we can add more `.where()` calls to it:\n\n{* ./docs_src/tutorial/where/tutorial007_py310.py ln[42:47] hl[44] *}\n\nThis will select the rows `WHERE` the `age` is **greater than or equal** to `35`, `AND` also the `age` is **less than** `40`.\n\nThe equivalent SQL would be:\n\n```SQL hl_lines=\"3\"\nSELECT id, name, secret_name, age\nFROM hero\nWHERE age >= 35 AND age < 40\n```\n\nThis uses `AND` to put both comparisons together.\n\nWe can then run it to see the output from the program:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT statement with WHERE, also using AND\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age >= ? AND hero.age < ?\nINFO Engine [no key 0.00014s] (35, 40)\n\n// The two heroes printed\nage=35 id=5 name='Black Lion' secret_name='Trevor Challa'\nage=36 id=6 name='Dr. Weird' secret_name='Steve Weird'\n\n```\n\n</div>\n\n## `.where()` With Multiple Expressions\n\nAs an alternative to using multiple `.where()` we can also pass several expressions to a single `.where()`:\n\n{* ./docs_src/tutorial/where/tutorial008_py310.py ln[42:47] hl[44] *}\n\nThis is the same as the above, and will result in the same output with the two heroes:\n\n```\nage=35 id=5 name='Black Lion' secret_name='Trevor Challa'\nage=36 id=6 name='Dr. Weird' secret_name='Steve Weird'\n```\n\n## `.where()` With Multiple Expressions Using `OR`\n\nThese last examples use `where()` with multiple expressions. And then those are combined in the final SQL using `AND`, which means that *all* of the expressions must be true in a row for it to be included in the results.\n\nBut we can also combine expressions using `OR`. Which means that **any** (but not necessarily all) of the expressions should be true in a row for it to be included.\n\nTo do it, you can import `or_`:\n\n{* ./docs_src/tutorial/where/tutorial009_py310.py ln[1] hl[1] *}\n\nAnd then pass both expressions to `or_()` and put it inside `.where()`.\n\nFor example, here we select the heroes that are the youngest OR the oldest:\n\n{* ./docs_src/tutorial/where/tutorial009_py310.py ln[42:47] hl[44] *}\n\nWhen we run it, this generates the output:\n\n<div class=\"termy\">\n\n```console\n$ python app.py\n\n// Some boilerplate output omitted 😉\n\n// The SELECT statement with WHERE, also using OR 🔍\nINFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\nFROM hero\nWHERE hero.age <= ? OR hero.age > ?\nINFO Engine [no key 0.00021s] (35, 90)\n\n// The results include the youngest and oldest ✨\nsecret_name='Natalia Roman-on' age=32 id=4 name='Tarantula'\nsecret_name='Trevor Challa' age=35 id=5 name='Black Lion'\nsecret_name='Esteban Rogelios' age=93 id=7 name='Captain North America'\n```\n\n</div>\n\n## Type Annotations and Errors\n\nThere's a chance that your editor gives you an error when using these comparisons, like:\n\n```Python\nHero.age > 35\n```\n\nIt would be an error telling you that\n\n> `Hero.age` is potentially `None`, and you cannot compare `None` with `>`\n\nThis is because as we are using pure and plain Python annotations for the fields, `age` is indeed annotated as `int | None`.\n\nBy using this simple and standard Python type annotations we get the benefit of the extra simplicity and the inline error checks when creating or using instances. ✨\n\nAnd when we use these special **class attributes** in a `.where()`, during execution of the program, the special class attribute will know that the comparison only applies for the values that are not `NULL` in the database, and it will work correctly.\n\nBut the editor doesn't know that it's a special **class attribute**, so it tries to help us preventing an error (that in this case is a false alarm).\n\nNevertheless, we can easily fix. 🎉\n\nWe can tell the editor that this class attribute is actually a special **SQLModel** column (instead of an instance attribute with a normal value).\n\nTo do that, we can import `col()` (as short for \"column\"):\n\n{* ./docs_src/tutorial/where/tutorial011_py310.py ln[1] hl[1] *}\n\nAnd then put the **class attribute** inside `col()` when using it in a `.where()`:\n\n{* ./docs_src/tutorial/where/tutorial011_py310.py ln[42:47] hl[44] *}\n\nSo, now the comparison is not:\n\n```Python\nHero.age > 35\n```\n\n...but:\n\n```Python\ncol(Hero.age) > 35\n```\n\nAnd with that the editor knows this code is actually fine, because this is a special **SQLModel** column.\n\n/// tip\n\nThat `col()` will come handy later, giving autocompletion to several other things we can do with these special **class attributes** for columns.\n\nBut we'll get there later.\n\n///\n\n## Recap\n\nYou can use `.where()` with powerful expressions using **SQLModel** columns (the special class attributes) to filter the rows that you want. 🚀\n\nUp to now, the database would have been **looking through each one of the records** (rows) to find the ones that match what you want. If you have thousands or millions of records, this could be very **slow**. 😱\n\nIn the next section I'll tell you how to add **indexes** to the database, this is what will make the queries **very efficient**. 😎\n"
  },
  {
    "path": "docs/virtual-environments.md",
    "content": "# Virtual Environments\n\nWhen you work in Python projects you probably should use a **virtual environment** (or a similar mechanism) to isolate the packages you install for each project.\n\n/// info\n\nIf you already know about virtual environments, how to create them and use them, you might want to skip this section. 🤓\n\n///\n\n/// tip\n\nA **virtual environment** is different than an **environment variable**.\n\nAn **environment variable** is a variable in the system that can be used by programs.\n\nA **virtual environment** is a directory with some files in it.\n\n///\n\n/// info\n\nThis page will teach you how to use **virtual environments** and how they work.\n\nIf you are ready to adopt a **tool that manages everything** for you (including installing Python), try <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">uv</a>.\n\n///\n\n## Create a Project\n\nFirst, create a directory for your project.\n\nWhat I normally do is that I create a directory named `code` inside my home/user directory.\n\nAnd inside of that I create one directory per project.\n\n<div class=\"termy\">\n\n```console\n// Go to the home directory\n$ cd\n// Create a directory for all your code projects\n$ mkdir code\n// Enter into that code directory\n$ cd code\n// Create a directory for this project\n$ mkdir awesome-project\n// Enter into that project directory\n$ cd awesome-project\n```\n\n</div>\n\n## Create a Virtual Environment\n\nWhen you start working on a Python project **for the first time**, create a virtual environment **<abbr title=\"there are other options, this is a simple guideline\">inside your project</abbr>**.\n\n/// tip\n\nYou only need to do this **once per project**, not every time you work.\n\n///\n\n//// tab | `venv`\n\nTo create a virtual environment, you can use the `venv` module that comes with Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | What that command means\n\n* `python`: use the program called `python`\n* `-m`: call a module as a script, we'll tell it which module next\n* `venv`: use the module called `venv` that normally comes installed with Python\n* `.venv`: create the virtual environment in the new directory `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nIf you have <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">`uv`</a> installed, you can use it to create a virtual environment.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip\n\nBy default, `uv` will create a virtual environment in a directory called `.venv`.\n\nBut you could customize it passing an additional argument with the directory name.\n\n///\n\n////\n\nThat command creates a new virtual environment in a directory called `.venv`.\n\n/// details | `.venv` or other name\n\nYou could create the virtual environment in a different directory, but there's a convention of calling it `.venv`.\n\n///\n\n## Activate the Virtual Environment\n\nActivate the new virtual environment so that any Python command you run or package you install uses it.\n\n/// tip\n\nDo this **every time** you start a **new terminal session** to work on the project.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOr if you use Bash for Windows (e.g. <a href=\"https://gitforwindows.org/\" class=\"external-link\" target=\"_blank\">Git Bash</a>):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip\n\nEvery time you install a **new package** in that environment, **activate** the environment again.\n\nThis makes sure that if you use a **terminal (<abbr title=\"command line interface\">CLI</abbr>) program** installed by that package, you use the one from your virtual environment and not any other that could be installed globally, probably with a different version than what you need.\n\n///\n\n## Check the Virtual Environment is Active\n\nCheck that the virtual environment is active (the previous command worked).\n\n/// tip\n\nThis is **optional**, but it's a good way to **check** that everything is working as expected and you are using the virtual environment you intended.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nIf it shows the `python` binary at `.venv/bin/python`, inside of your project (in this case `awesome-project`), then it worked. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nIf it shows the `python` binary at `.venv\\Scripts\\python`, inside of your project (in this case `awesome-project`), then it worked. 🎉\n\n////\n\n## Upgrade `pip`\n\n/// tip\n\nIf you use <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">`uv`</a> you would use it to install things instead of `pip`, so you don't need to upgrade `pip`. 😎\n\n///\n\nIf you are using `pip` to install packages (it comes by default with Python), you should **upgrade** it to the latest version.\n\nMany exotic errors while installing a package are solved by just upgrading `pip` first.\n\n/// tip\n\nYou would normally do this **once**, right after you create the virtual environment.\n\n///\n\nMake sure the virtual environment is active (with the command above) and then run:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n## Add `.gitignore`\n\nIf you are using **Git** (you should), add a `.gitignore` file to exclude everything in your `.venv` from Git.\n\n/// tip\n\nIf you used <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">`uv`</a> to create the virtual environment, it already did this for you, you can skip this step. 😎\n\n///\n\n/// tip\n\nDo this **once**, right after you create the virtual environment.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | What that command means\n\n* `echo \"*\"`: will \"print\" the text `*` in the terminal (the next part changes that a bit)\n* `>`: anything printed to the terminal by the command to the left of `>` should not be printed but instead written to the file that goes to the right of `>`\n* `.gitignore`: the name of the file where the text should be written\n\nAnd `*` for Git means \"everything\". So, it will ignore everything in the `.venv` directory.\n\nThat command will create a file `.gitignore` with the content:\n\n```gitignore\n*\n```\n\n///\n\n## Install Packages\n\nAfter activating the environment, you can install packages in it.\n\n/// tip\n\nDo this **once** when installing or upgrading the packages your project needs.\n\nIf you need to upgrade a version or add a new package you would **do this again**.\n\n///\n\n### Install Packages Directly\n\nIf you're in a hurry and don't want to use a file to declare your project's package requirements, you can install them directly.\n\n/// tip\n\nIt's a (very) good idea to put the packages and versions your program needs in a file (for example `requirements.txt` or `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nIf you have <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">`uv`</a>:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n////\n\n### Install from `requirements.txt`\n\nIf you have a `requirements.txt`, you can now use it to install its packages.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nIf you have <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">`uv`</a>:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nA `requirements.txt` with some packages could look like:\n\n```requirements.txt\nsqlmodel==0.13.0\nrich==13.7.1\n```\n\n///\n\n## Run Your Program\n\nAfter you activated the virtual environment, you can run your program, and it will use the Python inside of your virtual environment with the packages you installed there.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Configure Your Editor\n\nYou would probably use an editor, make sure you configure it to use the same virtual environment you created (it will probably autodetect it) so that you can get autocompletion and inline errors.\n\nFor example:\n\n* <a href=\"https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment\" class=\"external-link\" target=\"_blank\">VS Code</a>\n* <a href=\"https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html\" class=\"external-link\" target=\"_blank\">PyCharm</a>\n\n/// tip\n\nYou normally have to do this only **once**, when you create the virtual environment.\n\n///\n\n## Deactivate the Virtual Environment\n\nOnce you are done working on your project you can **deactivate** the virtual environment.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nThis way, when you run `python` it won't try to run it from that virtual environment with the packages installed there.\n\n## Ready to Work\n\nNow you're ready to start working on your project.\n\n\n\n/// tip\n\nDo you want to understand what's all that above?\n\nContinue reading. 👇🤓\n\n///\n\n## Why Virtual Environments\n\nTo work with SQLModel you need to install <a href=\"https://www.python.org/\" class=\"external-link\" target=\"_blank\">Python</a>.\n\nAfter that, you would need to **install** SQLModel and any other **packages** you want to use.\n\nTo install packages you would normally use the `pip` command that comes with Python (or similar alternatives).\n\nNevertheless, if you just use `pip` directly, the packages would be installed in your **global Python environment** (the global installation of Python).\n\n### The Problem\n\nSo, what's the problem with installing packages in the global Python environment?\n\nAt some point, you will probably end up writing many different programs that depend on **different packages**. And some of these projects you work on will depend on **different versions** of the same package. 😱\n\nFor example, you could create a project called `philosophers-stone`, this program depends on another package called **`harry`, using the version `1`**. So, you need to install `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nThen, at some point later, you create another project called `prisoner-of-azkaban`, and this project also depends on `harry`, but this project needs **`harry` version `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nBut now the problem is, if you install the packages globally (in the global environment) instead of in a local **virtual environment**, you will have to choose which version of `harry` to install.\n\nIf you want to run `philosophers-stone` you will need to first install `harry` version `1`, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nAnd then you would end up with `harry` version `1` installed in your global Python environment.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nBut then if you want to run `prisoner-of-azkaban`, you will need to uninstall `harry` version `1` and install `harry` version `3` (or just installing version `3` would automatically uninstall version `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nAnd then you would end up with `harry` version `3` installed in your global Python environment.\n\nAnd if you try to run `philosophers-stone` again, there's a chance it would **not work** because it needs `harry` version `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip\n\nIt's very common in Python packages to try the best to **avoid breaking changes** in **new versions**, but it's better to be safe, and install newer versions intentionally and when you can run the tests to check everything is working correctly.\n\n///\n\nNow, imagine that with **many** other **packages** that all your **projects depend on**. That's very difficult to manage. And you would probably end up running some projects with some **incompatible versions** of the packages, and not knowing why something isn't working.\n\nAlso, depending on your operating system (e.g. Linux, Windows, macOS), it could have come with Python already installed. And in that case it probably had some packages pre-installed with some specific versions **needed by your system**. If you install packages in the global Python environment, you could end up **breaking** some of the programs that came with your operating system.\n\n## Where are Packages Installed\n\nWhen you install Python, it creates some directories with some files in your computer.\n\nSome of these directories are the ones in charge of having all the packages you install.\n\nWhen you run:\n\n<div class=\"termy\">\n\n```console\n// Don't run this now, it's just an example 🤓\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\nThat will download a compressed file with the SQLModel code, normally from <a href=\"https://pypi.org/project/sqlmodel/\" class=\"external-link\" target=\"_blank\">PyPI</a>.\n\nIt will also **download** files for other packages that SQLModel depends on.\n\nThen it will **extract** all those files and put them in a directory in your computer.\n\nBy default, it will put those files downloaded and extracted in the directory that comes with your Python installation, that's the **global environment**.\n\n## What are Virtual Environments\n\nThe solution to the problems of having all the packages in the global environment is to use a **virtual environment for each project** you work on.\n\nA virtual environment is a **directory**, very similar to the global one, where you can install the packages for a project.\n\nThis way, each project will have its own virtual environment (`.venv` directory) with its own packages.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## What Does Activating a Virtual Environment Mean\n\nWhen you activate a virtual environment, for example with:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOr if you use Bash for Windows (e.g. <a href=\"https://gitforwindows.org/\" class=\"external-link\" target=\"_blank\">Git Bash</a>):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nThat command will create or modify some [environment variables](environment-variables.md){.internal-link target=_blank} that will be available for the next commands.\n\nOne of those variables is the `PATH` variable.\n\n/// tip\n\nYou can learn more about the `PATH` environment variable in the [Environment Variables](environment-variables.md#path-environment-variable){.internal-link target=_blank} section.\n\n///\n\nActivating a virtual environment adds its path `.venv/bin` (on Linux and macOS) or `.venv\\Scripts` (on Windows) to the `PATH` environment variable.\n\nLet's say that before activating the environment, the `PATH` variable looked like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThat means that the system would look for programs in:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nThat means that the system would look for programs in:\n\n* `C:\\Windows\\System32`\n\n////\n\nAfter activating the virtual environment, the `PATH` variable would look something like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThat means that the system will now start looking first for programs in:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nbefore looking in the other directories.\n\nSo, when you type `python` in the terminal, the system will find the Python program in\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nand use that one.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nThat means that the system will now start looking first look for programs in:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nbefore looking in the other directories.\n\nSo, when you type `python` in the terminal, the system will find the Python program in\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nand use that one.\n\n////\n\nAn important detail is that it will put the virtual environment path at the **beginning** of the `PATH` variable. The system will find it **before** finding any other Python available. This way, when you run `python`, it will use the Python **from the virtual environment** instead of any other `python` (for example, a `python` from a global environment).\n\nActivating a virtual environment also changes a couple of other things, but this is one of the most important things it does.\n\n## Checking a Virtual Environment\n\nWhen you check if a virtual environment is active, for example with:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nThat means that the `python` program that will be used is the one **in the virtual environment**.\n\nyou use `which` in Linux and macOS and `Get-Command` in Windows PowerShell.\n\nThe way that command works is that it will go and check in the `PATH` environment variable, going through **each path in order**, looking for the program called `python`. Once it finds it, it will **show you the path** to that program.\n\nThe most important part is that when you call `python`, that is the exact \"`python`\" that will be executed.\n\nSo, you can confirm if you are in the correct virtual environment.\n\n/// tip\n\nIt's easy to activate one virtual environment, get one Python, and then **go to another project**.\n\nAnd the second project **wouldn't work** because you are using the **incorrect Python**, from a virtual environment for another project.\n\nIt's useful being able to check what `python` is being used. 🤓\n\n///\n\n## Why Deactivate a Virtual Environment\n\nFor example, you could be working on a project `philosophers-stone`, **activate that virtual environment**, install packages and work with that environment.\n\nAnd then you want to work on **another project** `prisoner-of-azkaban`.\n\nYou go to that project:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nIf you don't deactivate the virtual environment for `philosophers-stone`, when you run `python` in the terminal, it will try to use the Python from `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importing sirius, it's not installed 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nBut if you deactivate the virtual environment and activate the new one for `prisoner-of-askaban` then when you run `python` it will use the Python from the virtual environment in `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎\n$ deactivate\n\n// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Now when you run python, it will find the package sirius installed in this virtual environment ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternatives\n\nThis is a simple guide to get you started and teach you how everything works **underneath**.\n\nThere are many **alternatives** to managing virtual environments, package dependencies (requirements), projects.\n\nOnce you are ready and want to use a tool to **manage the entire project**, packages dependencies, virtual environments, etc. I would suggest you try <a href=\"https://github.com/astral-sh/uv\" class=\"external-link\" target=\"_blank\">uv</a>.\n\n`uv` can do a lot of things, it can:\n\n* **Install Python** for you, including different versions\n* Manage the **virtual environment** for your projects\n* Install **packages**\n* Manage package **dependencies and versions** for your project\n* Make sure you have an **exact** set of packages and versions to install, including their dependencies, so that you can be sure that you can run your project in production exactly the same as in your computer while developing, this is called **locking**\n* And many other things\n\n## Conclusion\n\nIf you read and understood all this, now **you know much more** about virtual environments than many developers out there. 🤓\n\nKnowing these details will most probably be useful in a future time when you are debugging something that seems complex, but you will know **how it all works underneath**. 😎\n"
  },
  {
    "path": "docs_src/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/advanced/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/advanced/decimal/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/advanced/decimal/tutorial001_py310.py",
    "content": "from decimal import Decimal\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n    money: Decimal = Field(default=0, max_digits=5, decimal_places=3)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\", money=1.1)\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\", money=0.001)\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, money=2.2)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Deadpond\")\n        results = session.exec(statement)\n        hero_1 = results.one()\n        print(\"Hero 1:\", hero_1)\n\n        statement = select(Hero).where(Hero.name == \"Rusty-Man\")\n        results = session.exec(statement)\n        hero_2 = results.one()\n        print(\"Hero 2:\", hero_2)\n\n        total_money = hero_1.money + hero_2.money\n        print(f\"Total money: {total_money}\")\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/advanced/uuid/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/advanced/uuid/tutorial001_py310.py",
    "content": "import uuid\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_hero():\n    with Session(engine) as session:\n        hero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n        print(\"The hero before saving in the DB\")\n        print(hero)\n        print(\"The hero ID was already set\")\n        print(hero.id)\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        print(\"After saving in the DB\")\n        print(hero)\n\n\ndef select_hero():\n    with Session(engine) as session:\n        hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_2)\n        session.commit()\n        session.refresh(hero_2)\n        hero_id = hero_2.id\n        print(\"Created hero:\")\n        print(hero_2)\n        print(\"Created hero ID:\")\n        print(hero_id)\n\n        statement = select(Hero).where(Hero.id == hero_id)\n        selected_hero = session.exec(statement).one()\n        print(\"Selected hero:\")\n        print(selected_hero)\n        print(\"Selected hero ID:\")\n        print(selected_hero.id)\n\n\ndef main() -> None:\n    create_db_and_tables()\n    create_hero()\n    select_hero()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/advanced/uuid/tutorial002_py310.py",
    "content": "import uuid\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_hero():\n    with Session(engine) as session:\n        hero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n        print(\"The hero before saving in the DB\")\n        print(hero)\n        print(\"The hero ID was already set\")\n        print(hero.id)\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        print(\"After saving in the DB\")\n        print(hero)\n\n\ndef select_hero():\n    with Session(engine) as session:\n        hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_2)\n        session.commit()\n        session.refresh(hero_2)\n        hero_id = hero_2.id\n        print(\"Created hero:\")\n        print(hero_2)\n        print(\"Created hero ID:\")\n        print(hero_id)\n\n        selected_hero = session.get(Hero, hero_id)\n        print(\"Selected hero:\")\n        print(selected_hero)\n        print(\"Selected hero ID:\")\n        print(selected_hero.id)\n\n\ndef main() -> None:\n    create_db_and_tables()\n    create_hero()\n    select_hero()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/automatic_id_none_refresh/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md",
    "content": "1. Create the `hero_1`.\n\n    **Doesn't generate any output**.\n\n2. Create the `hero_2`.\n\n    **Doesn't generate any output**.\n\n3. Create the `hero_3`.\n\n    **Doesn't generate any output**.\n\n4. Print the line `\"Before interacting with the database\"`.\n\n    Generates the output:\n\n    ```\n    Before interacting with the database\n    ```\n\n5. Print the `hero_1` before interacting with the database.\n\n    Generates the output:\n\n    ```\n    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\n    ```\n\n6. Print the `hero_2` before interacting with the database.\n\n    Generates the output:\n\n    ```\n    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\n    ```\n\n7. Print the `hero_3` before interacting with the database.\n\n    Generates the output:\n\n    ```\n    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\n    ```\n\n8. Create the `Session` in a `with` block.\n\n    **Doesn't generate any output**.\n\n9. Add the `hero_1` to the session.\n\n    This still doesn't save it to the database.\n\n    **Doesn't generate any output**.\n\n10. Add the `hero_2` to the session.\n\n    This still doesn't save it to the database.\n\n    **Doesn't generate any output**.\n\n11. Add the `hero_3` to the session.\n\n    This still doesn't save it to the database.\n\n    **Doesn't generate any output**.\n\n12. Print the line `\"After adding to the session\"`.\n\n    Generates the output:\n\n    ```\n    After adding to the session\n    ```\n\n13. Print the `hero_1` after adding it to the session.\n\n    It still has the same data as there hasn't been any interaction with the database yet. Notice that the `id` is still `None`.\n\n    Generates the output:\n\n    ```\n    Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None\n    ```\n\n14. Print the `hero_2` after adding it to the session.\n\n    It still has the same data as there hasn't been any interaction with the database yet. Notice that the `id` is still `None`.\n\n    Generates the output:\n\n    ```\n    Hero 2: id=None name='Spider-Boy' secret_name='Pedro Parqueador' age=None\n    ```\n\n15. Print the `hero_3` after adding it to the session.\n\n    It still has the same data as there hasn't been any interaction with the database yet. Notice that the `id` is still `None`.\n\n    Generates the output:\n\n    ```\n    Hero 3: id=None name='Rusty-Man' secret_name='Tommy Sharp' age=48\n    ```\n\n16. `commit` the **session**.\n\n    This will **save** all the data to the database. The **session** will use the **engine** to run a lot of SQL.\n\n    Generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\n    INFO Engine [generated in 0.00018s] ('Deadpond', 'Dive Wilson', None)\n    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\n    INFO Engine [cached since 0.0008968s ago] ('Spider-Boy', 'Pedro Parqueador', None)\n    INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?)\n    INFO Engine [cached since 0.001143s ago] ('Rusty-Man', 'Tommy Sharp', 48)\n    INFO Engine COMMIT\n    ```\n\n17. Print the line `\"After committing the session\"`.\n\n    Generates the output:\n\n    ```\n    After committing the session\n    ```\n\n18. Print the `hero_1` after committing the session.\n\n    The `hero_1` is now internally marked as expired, and until it is refreshed, it looks like if it didn't contain any data.\n\n    Generates the output:\n\n    ```\n    Hero 1:\n    ```\n\n19. Print the `hero_2` after committing the session.\n\n    The `hero_2` is now internally marked as expired, and until it is refreshed, it looks like if it didn't contain any data.\n\n    Generates the output:\n\n    ```\n    Hero 2:\n    ```\n\n20. Print the `hero_3` after committing the session.\n\n    The `hero_3` is now internally marked as expired, and until it is refreshed, it looks like if it didn't contain any data.\n\n    Generates the output:\n\n    ```\n    Hero 3:\n    ```\n\n21. Print the line `\"After committing the session, show IDs\"`.\n\n    Generates the output:\n\n    ```\n    After committing the session, show IDs\n    ```\n\n22. Print the `hero_1.id`. A lot happens here.\n\n    Because we are accessing the attribute `id` of `hero_1`, **SQLModel** (actually SQLAlchemy) can detect that we are trying to access data from the `hero_1`.\n\n    It then detects that `hero_1` is currently associated with a **session** (because we added it to the session and committed it), and it is marked as expired.\n\n    Then with the **session**, it uses the **engine** to execute all the SQL to fetch the data for this object from the database.\n\n    Next it updates the object with the new data and marks it internally as \"fresh\" or \"not expired\".\n\n    Finally, it makes the ID value available for the rest of the Python expression. In this case, the Python expression just prints the ID.\n\n    Generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [generated in 0.00017s] (1,)\n\n    Hero 1 ID: 1\n    ```\n\n23. Print the `hero_2.id`.\n\n    A lot happens here, all the same stuff that happened at point 22, but for this `hero_2` object.\n\n    Generates the output:\n\n    ```\n    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [cached since 0.001245s ago] (2,)\n\n    Hero 2 ID: 2\n    ```\n\n24. Print the `hero_3.id`.\n\n    A lot happens here, all the same stuff that happened at point 22, but for this `hero_3` object.\n\n    Generates the output:\n\n    ```\n    INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [cached since 0.002215s ago] (3,)\n\n\n    Hero 3 ID: 3\n    ```\n\n25. Print the line `\"After committing the session, show names\"`.\n\n    Generates the output:\n\n    ```\n    After committing the session, show names\n    ```\n\n26. Print the `hero_1.name`.\n\n    Because `hero_1` is still fresh, no additional data is fetched, no additional SQL is executed, and the name is available.\n\n    Generates the output:\n\n    ```\n    Hero 1 name: Deadpond\n    ```\n\n27. Print the `hero_2.name`.\n\n    Because `hero_2` is still fresh, no additional data is fetched, no additional SQL is executed, and the name is available.\n\n    Generates the output:\n\n    ```\n    Hero 2 name: Spider-Boy\n    ```\n\n28. Print the `hero_3.name`.\n\n    Because `hero_3` is still fresh, no additional data is fetched, no additional SQL is executed, and the name is available.\n\n    Generates the output:\n\n    ```\n    Hero 3 name: Rusty-Man\n    ```\n\n29. Explicitly refresh the `hero_1` object.\n\n    The **session** will use the **engine** to execute the SQL necessary to fetch fresh data from the database for the `hero_1` object.\n\n    Generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [generated in 0.00024s] (1,)\n    ```\n\n30. Explicitly refresh the `hero_2` object.\n\n    The **session** will use the **engine** to execute the SQL necessary to fetch fresh data from the database for the `hero_2` object.\n\n    Generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [cached since 0.001487s ago] (2,)\n    ```\n\n31. Explicitly refresh the `hero_3` object.\n\n    The **session** will use the **engine** to execute the SQL necessary to fetch fresh data from the database for the `hero_3` object.\n\n    Generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [cached since 0.002377s ago] (3,)\n    ```\n\n32. Print the line `\"After refreshing the heroes\"`.\n\n    Generates the output:\n\n    ```\n    After refreshing the heroes\n    ```\n\n33. Print the `hero_1`.\n\n    /// info\n\n    Even if the `hero_1` wasn't fresh, this would **not** trigger a `refresh` making the **session** use the **engine** to fetch data from the database because it is not accessing an attribute.\n\n    ///\n\n    Because the `hero_1` is fresh it has all it's data available.\n\n    Generates the output:\n\n    ```\n    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\n    ```\n\n34. Print the `hero_2`.\n\n    /// info\n\n    Even if the `hero_2` wasn't fresh, this would **not** trigger a `refresh` making the **session** use the **engine** to fetch data from the database because it is not accessing an attribute.\n\n    ///\n\n    Because the `hero_2` is fresh it has all it's data available.\n\n    Generates the output:\n\n    ```\n    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\n    ```\n\n35. Print the `hero_3`.\n\n    /// info\n\n    Even if the `hero_3` wasn't fresh, this would **not** trigger a `refresh` making the **session** use the **engine** to fetch data from the database because it is not accessing an attribute.\n\n    ///\n\n    Because the `hero_3` is fresh it has all it's data available.\n\n    Generates the output:\n\n    ```\n    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\n    ```\n\n36. The `with` block ends here (there's no more indented code), so the **session** is closed, running all it's closing code.\n\n    This includes doing a `ROLLBACK` of any possible transaction that could have been started.\n\n    Generates the output:\n\n    ```\n    INFO Engine ROLLBACK\n    ```\n\n37. Print the line `\"After the session closes\"`.\n\n    Generates the output:\n\n    ```\n    After the session closes\n    ```\n\n38. Print the `hero_1` after closing the session.\n\n    Generates the output:\n\n    ```\n    Hero 1: age=None id=1 name='Deadpond' secret_name='Dive Wilson'\n    ```\n\n39. Print the `hero_2` after closing the session.\n\n    Generates the output:\n\n    ```\n    Hero 2: age=None id=2 name='Spider-Boy' secret_name='Pedro Parqueador'\n    ```\n\n40. Print the `hero_3` after closing the session.\n\n    Generates the output:\n\n    ```\n    Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'\n    ```\n"
  },
  {
    "path": "docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    print(\"Before interacting with the database\")\n    print(\"Hero 1:\", hero_1)\n    print(\"Hero 2:\", hero_2)\n    print(\"Hero 3:\", hero_3)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        print(\"After adding to the session\")\n        print(\"Hero 1:\", hero_1)\n        print(\"Hero 2:\", hero_2)\n        print(\"Hero 3:\", hero_3)\n\n        session.commit()\n\n        print(\"After committing the session\")\n        print(\"Hero 1:\", hero_1)\n        print(\"Hero 2:\", hero_2)\n        print(\"Hero 3:\", hero_3)\n\n        print(\"After committing the session, show IDs\")\n        print(\"Hero 1 ID:\", hero_1.id)\n        print(\"Hero 2 ID:\", hero_2.id)\n        print(\"Hero 3 ID:\", hero_3.id)\n\n        print(\"After committing the session, show names\")\n        print(\"Hero 1 name:\", hero_1.name)\n        print(\"Hero 2 name:\", hero_2.name)\n        print(\"Hero 3 name:\", hero_3.name)\n\n        session.refresh(hero_1)\n        session.refresh(hero_2)\n        session.refresh(hero_3)\n\n        print(\"After refreshing the heroes\")\n        print(\"Hero 1:\", hero_1)\n        print(\"Hero 2:\", hero_2)\n        print(\"Hero 3:\", hero_3)\n\n    print(\"After the session closes\")\n    print(\"Hero 1:\", hero_1)\n    print(\"Hero 2:\", hero_2)\n    print(\"Hero 3:\", hero_3)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/automatic_id_none_refresh/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")  # (1)!\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")  # (2)!\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)  # (3)!\n\n    print(\"Before interacting with the database\")  # (4)!\n    print(\"Hero 1:\", hero_1)  # (5)!\n    print(\"Hero 2:\", hero_2)  # (6)!\n    print(\"Hero 3:\", hero_3)  # (7)!\n\n    with Session(engine) as session:  # (8)!\n        session.add(hero_1)  # (9)!\n        session.add(hero_2)  # (10)!\n        session.add(hero_3)  # (11)!\n\n        print(\"After adding to the session\")  # (12)!\n        print(\"Hero 1:\", hero_1)  # (13)!\n        print(\"Hero 2:\", hero_2)  # (14)!\n        print(\"Hero 3:\", hero_3)  # (15)!\n\n        session.commit()  # (16)!\n\n        print(\"After committing the session\")  # (17)!\n        print(\"Hero 1:\", hero_1)  # (18)!\n        print(\"Hero 2:\", hero_2)  # (19)!\n        print(\"Hero 3:\", hero_3)  # (20)!\n\n        print(\"After committing the session, show IDs\")  # (21)!\n        print(\"Hero 1 ID:\", hero_1.id)  # (22)!\n        print(\"Hero 2 ID:\", hero_2.id)  # (23)!\n        print(\"Hero 3 ID:\", hero_3.id)  # (24)!\n\n        print(\"After committing the session, show names\")  # (25)!\n        print(\"Hero 1 name:\", hero_1.name)  # (26)!\n        print(\"Hero 2 name:\", hero_2.name)  # (27)!\n        print(\"Hero 3 name:\", hero_3.name)  # (28)!\n\n        session.refresh(hero_1)  # (29)!\n        session.refresh(hero_2)  # (30)!\n        session.refresh(hero_3)  # (31)!\n\n        print(\"After refreshing the heroes\")  # (32)!\n        print(\"Hero 1:\", hero_1)  # (33)!\n        print(\"Hero 2:\", hero_2)  # (34)!\n        print(\"Hero 3:\", hero_3)  # (35)!\n    # (36)!\n\n    print(\"After the session closes\")  # (37)!\n    print(\"Hero 1:\", hero_1)  # (38)!\n    print(\"Hero 2:\", hero_2)  # (39)!\n    print(\"Hero 3:\", hero_3)  # (40)!\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial001_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial001_py310/app.py",
    "content": "from sqlmodel import Session\n\nfrom .database import create_db_and_tables, engine\nfrom .models import Hero, Team\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        session.add(hero_deadpond)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Hero's team:\", hero_deadpond.team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial001_py310/database.py",
    "content": "from sqlmodel import SQLModel, create_engine\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial001_py310/models.py",
    "content": "from sqlmodel import Field, Relationship, SQLModel\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial002_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial002_py310/app.py",
    "content": "from sqlmodel import Session\n\nfrom .database import create_db_and_tables, engine\nfrom .hero_model import Hero\nfrom .team_model import Team\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        session.add(hero_deadpond)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Hero's team:\", hero_deadpond.team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial002_py310/database.py",
    "content": "from sqlmodel import SQLModel, create_engine\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial002_py310/hero_model.py",
    "content": "from typing import TYPE_CHECKING, Optional\n\nfrom sqlmodel import Field, Relationship, SQLModel\n\nif TYPE_CHECKING:\n    from .team_model import Team\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Optional[\"Team\"] = Relationship(back_populates=\"heroes\")\n"
  },
  {
    "path": "docs_src/tutorial/code_structure/tutorial002_py310/team_model.py",
    "content": "from typing import TYPE_CHECKING\n\nfrom sqlmodel import Field, Relationship, SQLModel\n\nif TYPE_CHECKING:\n    from .hero_model import Hero\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n"
  },
  {
    "path": "docs_src/tutorial/connect/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/create_tables/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/create_tables/tutorial001_py310.py",
    "content": "from sqlmodel import Field, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef main():\n    create_db_and_tables()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/delete/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/delete/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team_id = team_preventers.id\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_spider_boy.team_id = None\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"No longer Preventer:\", hero_spider_boy)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/insert/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/insert/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/select/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/select/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero, Team).where(Hero.team_id == Team.id)\n        results = session.exec(statement)\n        for hero, team in results:\n            print(\"Hero:\", hero, \"Team:\", team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/select/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero, Team).join(Team)\n        results = session.exec(statement)\n        for hero, team in results:\n            print(\"Hero:\", hero, \"Team:\", team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/select/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero, Team).join(Team, isouter=True)\n        results = session.exec(statement)\n        for hero, team in results:\n            print(\"Hero:\", hero, \"Team:\", team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/select/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).join(Team).where(Team.name == \"Preventers\")\n        results = session.exec(statement)\n        for hero in results:\n            print(\"Preventer Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/select/tutorial005_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero, Team).join(Team).where(Team.name == \"Preventers\")\n        results = session.exec(statement)\n        for hero, team in results:\n            print(\"Preventer Hero:\", hero, \"Team:\", team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/connect/update/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/connect/update/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n        session.add(team_preventers)\n        session.add(team_z_force)\n        session.commit()\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team_id=team_z_force.id\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            team_id=team_preventers.id,\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team_id = team_preventers.id\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/create_db_and_table/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md",
    "content": "1. Import `Optional` from `typing` to declare fields that could be `None`.\n2. Import the things we will need from `sqlmodel`: `Field`, `SQLModel`, `create_engine`.\n3. Create the `Hero` model class, representing the `hero` table in the database.\n\n    And also mark this class as a **table model** with `table=True`.\n\n4. Create the `id` field:\n\n    It could be `None` until the database assigns a value to it, so we annotate it with `Optional` (`int | None` in Python 3.10+).\n\n    It is a **primary key**, so we use `Field()` and the argument `primary_key=True`.\n\n5. Create the `name` field.\n\n    It is required, so there's no default value, and it's not `Optional`.\n\n6. Create the `secret_name` field.\n\n    Also required.\n\n7. Create the `age` field.\n\n    It is not required, the default value is `None`.\n\n    In the database, the default value will be `NULL`, the SQL equivalent of `None`.\n\n    As this field could be `None` (and `NULL` in the database), we annotate it with `Optional` (`int | None` in Python 3.10+).\n\n8. Write the name of the database file.\n9. Use the name of the database file to create the database URL.\n10. Create the engine using the URL.\n\n    This doesn't create the database yet, no file or table is created at this point, only the **engine** object that will handle the connections with this specific database, and with specific support for SQLite (based on the URL).\n\n11. Put the code that creates side effects in a function.\n\n    In this case, only one line that creates the database file with the table.\n\n12. Create all the tables that were automatically registered in `SQLModel.metadata`.\n\n13. Add a main block, or \"Top-level script environment\".\n\n    And put some logic to be executed when this is called directly with Python, as in:\n\n    <div class=\"termy\">\n\n    ```console\n    $ python app.py\n\n    // Execute all the stuff and show the output\n    ```\n\n    </div>\n\n    ...but that is not executed when importing something from this module, like:\n\n    ```Python\n    from app import Hero\n    ```\n\n14. In this main block, call the function that creates the database file and the table.\n\n    This way when we call it with:\n\n    <div class=\"termy\">\n\n    ```console\n    $ python app.py\n\n    // Doing stuff ✨\n    ```\n\n    </div>\n\n    ...it will create the database file and the table.\n"
  },
  {
    "path": "docs_src/tutorial/create_db_and_table/tutorial001_py310.py",
    "content": "from sqlmodel import Field, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\nSQLModel.metadata.create_all(engine)\n"
  },
  {
    "path": "docs_src/tutorial/create_db_and_table/tutorial002_py310.py",
    "content": "from sqlmodel import Field, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\nif __name__ == \"__main__\":\n    create_db_and_tables()\n"
  },
  {
    "path": "docs_src/tutorial/create_db_and_table/tutorial003_py310.py",
    "content": "from sqlmodel import Field, SQLModel, create_engine  # (2)!\n\n\nclass Hero(SQLModel, table=True):  # (3)!\n    id: int | None = Field(default=None, primary_key=True)  # (4)!\n    name: str  # (5)!\n    secret_name: str  # (6)!\n    age: int | None = None  # (7)!\n\n\nsqlite_file_name = \"database.db\"  # (8)!\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"  # (9)!\n\nengine = create_engine(sqlite_url, echo=True)  # (10)!\n\n\ndef create_db_and_tables():  # (11)!\n    SQLModel.metadata.create_all(engine)  # (12)!\n\n\nif __name__ == \"__main__\":  # (13)!\n    create_db_and_tables()  # (14)!\n"
  },
  {
    "path": "docs_src/tutorial/delete/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/delete/annotations/en/tutorial002.md",
    "content": "1. Select the hero we will delete.\n\n2. Execute the query with the select statement object.\n\n    This generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.name = ?\n    INFO Engine [no key 0.00011s] ('Spider-Youngster',)\n    ```\n\n3. Get one hero object, expecting exactly one.\n\n    /// tip\n\n    This ensures there's no more than one, and that there's exactly one, not `None`.\n\n    This would never return `None`, instead it would raise an exception.\n\n    ///\n\n4. Print the hero object.\n\n    This generates the output:\n\n    ```\n    Hero:  name='Spider-Youngster' secret_name='Pedro Parqueador' age=16 id=2\n    ```\n\n5. Delete the hero from the **session**.\n\n    This marks the hero as deleted from the session, but it will not be removed from the database until we **commit** the changes.\n\n6. Commit the session.\n\n    This saves the changes in the session, including deleting this row.\n\n    It generates the output:\n\n    ```\n    INFO Engine DELETE FROM hero WHERE hero.id = ?\n    INFO Engine [generated in 0.00020s] (2,)\n    INFO Engine COMMIT\n    ```\n\n7. Print the deleted hero object.\n\n    The hero is deleted in the database. And is marked as deleted in the session.\n\n    But we still have the object in memory with its data, so we can use it to print it.\n\n    This generates the output:\n\n    ```\n    Deleted hero: name='Spider-Youngster' secret_name='Pedro Parqueador' age=16 id=2\n    ```\n\n8. Select the same hero again.\n\n    We'll do this to confirm if the hero is really deleted.\n\n9. Execute the select statement.\n\n    This generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.name = ?\n    INFO Engine [no key 0.00013s] ('Spider-Youngster',)\n    ```\n\n10. Get the \"first\" item from the `results`.\n\n    If no items were found, this will return `None`, which is what we expect.\n\n11. Check if the first item from the results is `None`.\n\n12. If this first item is indeed `None`, it means that it was correctly deleted from the database.\n\n    Now we can print a message to confirm.\n\n    This generates the output:\n\n    ```\n    There's no hero named Spider-Youngster\n    ```\n\n13. This is the end of the `with` block, here the **session** executes its closing code.\n\n    This generates the output:\n\n    ```\n    INFO Engine ROLLBACK\n    ```\n"
  },
  {
    "path": "docs_src/tutorial/delete/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        results = session.exec(statement)\n        hero_1 = results.one()\n        print(\"Hero 1:\", hero_1)\n\n        statement = select(Hero).where(Hero.name == \"Captain North America\")\n        results = session.exec(statement)\n        hero_2 = results.one()\n        print(\"Hero 2:\", hero_2)\n\n        hero_1.age = 16\n        hero_1.name = \"Spider-Youngster\"\n        session.add(hero_1)\n\n        hero_2.name = \"Captain North America Except Canada\"\n        hero_2.age = 110\n        session.add(hero_2)\n\n        session.commit()\n        session.refresh(hero_1)\n        session.refresh(hero_2)\n\n        print(\"Updated hero 1:\", hero_1)\n        print(\"Updated hero 2:\", hero_2)\n\n\ndef delete_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Youngster\")\n        results = session.exec(statement)\n        hero = results.one()\n        print(\"Hero: \", hero)\n\n        session.delete(hero)\n        session.commit()\n\n        print(\"Deleted hero:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Spider-Youngster\")\n        results = session.exec(statement)\n        hero = results.first()\n\n        if hero is None:\n            print(\"There's no hero named Spider-Youngster\")\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n    delete_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/delete/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        results = session.exec(statement)\n        hero_1 = results.one()\n        print(\"Hero 1:\", hero_1)\n\n        statement = select(Hero).where(Hero.name == \"Captain North America\")\n        results = session.exec(statement)\n        hero_2 = results.one()\n        print(\"Hero 2:\", hero_2)\n\n        hero_1.age = 16\n        hero_1.name = \"Spider-Youngster\"\n        session.add(hero_1)\n\n        hero_2.name = \"Captain North America Except Canada\"\n        hero_2.age = 110\n        session.add(hero_2)\n\n        session.commit()\n        session.refresh(hero_1)\n        session.refresh(hero_2)\n\n        print(\"Updated hero 1:\", hero_1)\n        print(\"Updated hero 2:\", hero_2)\n\n\ndef delete_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Youngster\")  # (1)!\n        results = session.exec(statement)  # (2)!\n        hero = results.one()  # (3)!\n        print(\"Hero: \", hero)  # (4)!\n\n        session.delete(hero)  # (5)!\n        session.commit()  # (6)!\n\n        print(\"Deleted hero:\", hero)  # (7)!\n\n        statement = select(Hero).where(Hero.name == \"Spider-Youngster\")  # (8)!\n        results = session.exec(statement)  # (9)!\n        hero = results.first()  # (10)!\n\n        if hero is None:  # (11)!\n            print(\"There's no hero named Spider-Youngster\")  # (12)!\n    # (13)!\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n    delete_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_001.md",
    "content": "1. Import the `app` from the the `main` module.\n\n2. We create a `TestClient` for the FastAPI `app` and put it in the variable `client`.\n\n3. Then we use use this `client` to **talk to the API** and send a `POST` HTTP operation, creating a new hero.\n\n4. Then we get the **JSON data** from the response and put it in the variable `data`.\n\n5. Next we start testing the results with `assert` statements, we check that the status code of the response is `200`.\n\n6. We check that the `name` of the hero created is `\"Deadpond\"`.\n\n7. We check that the `secret_name` of the hero created is `\"Dive Wilson\"`.\n\n8. We check that the `age` of the hero created is `None`, because we didn't send an age.\n\n9. We check that the hero created has an `id` created by the database, so it's not `None`.\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_002.md",
    "content": "1. Import the `get_session` dependency from the the `main` module.\n\n2. Define the new function that will be the new **dependency override**.\n\n3. This function will return a different **session** than the one that would be returned by the original `get_session` function.\n\n    We haven't seen how this new **session** object is created yet, but the point is that this is a different session than the original one from the app.\n\n    This session is attached to a different **engine**, and that different **engine** uses a different URL, for a database just for testing.\n\n    We haven't defined that new **URL** nor the new **engine** yet, but here we already see the that this object `session` will override the one returned by the original dependency  `get_session()`.\n\n4. Then, the FastAPI `app` object has an attribute `app.dependency_overrides`.\n\n    This attribute is a dictionary, and we can put dependency overrides in it by passing, as the **key**, the **original dependency function**, and as the **value**, the **new overriding dependency function**.\n\n    So, here we are telling the FastAPI app to use `get_session_override` instead of `get_session` in all the places in the code that depend on `get_session`, that is, all the parameters with something like:\n\n    ```Python\n    session: Session = Depends(get_session)\n    ```\n\n5. After we are done with the dependency override, we can restore the application back to normal, by removing all the values in this dictionary `app.dependency_overrides`.\n\n    This way whenever a *path operation function* needs the dependency FastAPI will use the original one instead of the override.\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_003.md",
    "content": "1. Here's a subtle thing to notice.\n\n    Remember that [Order Matters](../create-db-and-table.md#sqlmodel-metadata-order-matters){.internal-link target=_blank} and we need to make sure all the **SQLModel** models are already defined and **imported** before calling `.create_all()`.\n\n    IN this line, by importing something, *anything*, from `.main`, the code in `.main` will be executed, including the definition of the **table models**, and that will automatically register them in `SQLModel.metadata`.\n\n2. Here we create a new **engine**, completely different from the one in `main.py`.\n\n    This is the engine we will use for the tests.\n\n    We use the new URL of the database for tests:\n\n    ```\n    sqlite:///testing.db\n    ```\n\n    And again, we use the connection argument `check_same_thread=False`.\n\n3. Then we call:\n\n    ```Python\n    SQLModel.metadata.create_all(engine)\n    ```\n\n    ...to make sure we create all the tables in the new testing database.\n\n    The **table models** are registered in `SQLModel.metadata` just because we imported *something* from `.main`, and the code in `.main` was executed, creating the classes for the **table models** and automatically registering them in `SQLModel.metadata`.\n\n    So, by the point we call this method, the **table models** are already registered there. 💯\n\n4. Here's where we create the custom **session** object for this test in a `with` block.\n\n    It uses the new custom **engine** we created, so anything that uses this session will be using the testing database.\n\n5. Now, back to the dependency override, it is just returning the same **session** object from outside, that's it, that's the whole trick.\n\n6. By this point, the testing **session** `with` block finishes, and the session is closed, the file is closed, etc.\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_004.md",
    "content": "1. Import `StaticPool` from `sqlmodel`, we will use it in a bit.\n\n2. For the **SQLite URL**, don't write any file name, leave it empty.\n\n    So, instead of:\n\n    ```\n    sqlite:///testing.db\n    ```\n\n    ...just write:\n\n    ```\n    sqlite://\n    ```\n\n    This is enough to tell **SQLModel** (actually SQLAlchemy) that we want to use an **in-memory SQLite database**.\n\n3. Remember that we told the **low-level** library in charge of communicating with SQLite that we want to be able to **access the database from different threads** with `check_same_thread=False`?\n\n    Now that we use an **in-memory database**, we need to also tell SQLAlchemy that we want to be able to use the **same in-memory database** object from different threads.\n\n    We tell it that with the `poolclass=StaticPool` parameter.\n\n    /// info\n\n    You can read more details in the <a href=\"https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-a-memory-database-in-multiple-threads\" class=\"external-link\" target=\"_blank\">SQLAlchemy documentation about Using a Memory Database in Multiple Threads</a>\n\n    ///\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_005.md",
    "content": "1. Import `pytest`.\n\n2. Use the `@pytest.fixture()` decorator on top of the function to tell pytest that this is a **fixture** function (equivalent to a FastAPI dependency).\n\n    We also give it a name of `\"session\"`, this will be important in the testing function.\n\n3. Create the fixture function. This is equivalent to a FastAPI dependency function.\n\n    In this fixture we create the custom **engine**, with the in-memory database, we create the tables, and we create the **session**.\n\n    Then we `yield` the `session` object.\n\n4. The thing that we `return` or `yield` is what will be available to the test function, in this case, the `session` object.\n\n    Here we use `yield` so that **pytest** comes back to execute \"the rest of the code\" in this function once the testing function is done.\n\n    We don't have any more visible \"rest of the code\" after the `yield`, but we have the end of the `with` block that will close the **session**.\n\n    By using `yield`, pytest will:\n\n    * run the first part\n    * create the **session** object\n    * give it to the test function\n    * run the test function\n    * once the test function is done, it will continue here, right after the `yield`, and will correctly close the **session** object in the end of the `with` block.\n\n5. Now, in the test function, to tell **pytest** that this test wants to get the fixture, instead of declaring something like in FastAPI with:\n\n    ```Python\n    session: Session = Depends(session_fixture)\n    ```\n\n    ...the way we tell pytest what is the fixture that we want is by using the **exact same name** of the fixture.\n\n    In this case, we named it `session`, so the parameter has to be exactly named `session` for it to work.\n\n    We also add the type annotation `session: Session` so that we can get autocompletion and inline error checks in our editor.\n\n6. Now in the dependency override function, we just return the same `session` object that came from outside it.\n\n    The `session` object comes from the parameter passed to the test function, and we just re-use it and return it here in the dependency override.\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_006.md",
    "content": "1. Create the new fixture named `\"client\"`.\n\n2. This **client fixture**, in turn, also requires the **session fixture**.\n\n3. Now we create the **dependency override** inside the client fixture.\n\n4. Set the **dependency override** in the `app.dependency_overrides` dictionary.\n\n5. Create the `TestClient` with the **FastAPI** `app`.\n\n6. `yield` the `TestClient` instance.\n\n    By using `yield`, after the test function is done, pytest will come back to execute the rest of the code after `yield`.\n\n7. This is the cleanup code, after `yield`, and after the test function is done.\n\n    Here we clear the dependency overrides (here it's only one) in the FastAPI `app`.\n\n8. Now the test function requires the **client fixture**.\n\n    And inside the test function, the code is quite **simple**, we just use the `TestClient` to make requests to the API, check the data, and that's it.\n\n    The fixtures take care of all the **setup** and **cleanup** code.\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/main.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(\n    *, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate\n):\n    db_hero = session.get(Hero, hero_id)\n    if not db_hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    db_hero.sqlmodel_update(hero_data)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_extra_coverage.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlalchemy import Inspector, inspect\nfrom sqlmodel import Session, create_engine\n\nfrom . import main as app_mod\nfrom .test_main import client_fixture, session_fixture\n\nassert client_fixture, \"This keeps the client fixture used below\"\nassert session_fixture, \"This keeps the session fixture used by client_fixture\"\n\n\ndef test_startup():\n    app_mod.engine = create_engine(\"sqlite://\")\n    app_mod.on_startup()\n    insp: Inspector = inspect(app_mod.engine)\n    assert insp.has_table(str(app_mod.Hero.__tablename__))\n\n\ndef test_get_session():\n    app_mod.engine = create_engine(\"sqlite://\")\n    for session in app_mod.get_session():\n        assert isinstance(session, Session)\n        assert session.bind == app_mod.engine\n\n\ndef test_read_hero_not_found(client: TestClient):\n    response = client.get(\"/heroes/9000\")\n    assert response.status_code == 404\n\n\ndef test_update_hero_not_found(client: TestClient):\n    response = client.patch(\"/heroes/9000\", json={\"name\": \"Very-Rusty-Man\"})\n    assert response.status_code == 404\n\n\ndef test_delete_hero_not_found(client: TestClient):\n    response = client.delete(\"/heroes/9000\")\n    assert response.status_code == 404\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom .main import Hero, app, get_session\n\n\n@pytest.fixture(name=\"session\")\ndef session_fixture():\n    engine = create_engine(\n        \"sqlite://\", connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as session:\n        yield session\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture(session: Session):\n    def get_session_override():\n        return session\n\n    app.dependency_overrides[get_session] = get_session_override\n    client = TestClient(app)\n    yield client\n    app.dependency_overrides.clear()\n\n\ndef test_create_hero(client: TestClient):\n    response = client.post(\n        \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n    )\n    data = response.json()\n\n    assert response.status_code == 200\n    assert data[\"name\"] == \"Deadpond\"\n    assert data[\"secret_name\"] == \"Dive Wilson\"\n    assert data[\"age\"] is None\n    assert data[\"id\"] is not None\n\n\ndef test_create_hero_incomplete(client: TestClient):\n    # No secret_name\n    response = client.post(\"/heroes/\", json={\"name\": \"Deadpond\"})\n    assert response.status_code == 422\n\n\ndef test_create_hero_invalid(client: TestClient):\n    # secret_name has an invalid type\n    response = client.post(\n        \"/heroes/\",\n        json={\n            \"name\": \"Deadpond\",\n            \"secret_name\": {\"message\": \"Do you wanna know my secret identity?\"},\n        },\n    )\n    assert response.status_code == 422\n\n\ndef test_read_heroes(session: Session, client: TestClient):\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    session.add(hero_1)\n    session.add(hero_2)\n    session.commit()\n\n    response = client.get(\"/heroes/\")\n    data = response.json()\n\n    assert response.status_code == 200\n\n    assert len(data) == 2\n    assert data[0][\"name\"] == hero_1.name\n    assert data[0][\"secret_name\"] == hero_1.secret_name\n    assert data[0][\"age\"] == hero_1.age\n    assert data[0][\"id\"] == hero_1.id\n    assert data[1][\"name\"] == hero_2.name\n    assert data[1][\"secret_name\"] == hero_2.secret_name\n    assert data[1][\"age\"] == hero_2.age\n    assert data[1][\"id\"] == hero_2.id\n\n\ndef test_read_hero(session: Session, client: TestClient):\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    session.add(hero_1)\n    session.commit()\n\n    response = client.get(f\"/heroes/{hero_1.id}\")\n    data = response.json()\n\n    assert response.status_code == 200\n    assert data[\"name\"] == hero_1.name\n    assert data[\"secret_name\"] == hero_1.secret_name\n    assert data[\"age\"] == hero_1.age\n    assert data[\"id\"] == hero_1.id\n\n\ndef test_update_hero(session: Session, client: TestClient):\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    session.add(hero_1)\n    session.commit()\n\n    response = client.patch(f\"/heroes/{hero_1.id}\", json={\"name\": \"Deadpuddle\"})\n    data = response.json()\n\n    assert response.status_code == 200\n    assert data[\"name\"] == \"Deadpuddle\"\n    assert data[\"secret_name\"] == \"Dive Wilson\"\n    assert data[\"age\"] is None\n    assert data[\"id\"] == hero_1.id\n\n\ndef test_delete_hero(session: Session, client: TestClient):\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    session.add(hero_1)\n    session.commit()\n\n    response = client.delete(f\"/heroes/{hero_1.id}\")\n\n    hero_in_db = session.get(Hero, hero_1.id)\n\n    assert response.status_code == 200\n\n    assert hero_in_db is None\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\n\nfrom .main import app, get_session  # (1)!\n\n\ndef test_create_hero():\n    engine = create_engine(\n        \"sqlite:///testing.db\", connect_args={\"check_same_thread\": False}\n    )\n    SQLModel.metadata.create_all(engine)\n\n    with Session(engine) as session:\n\n        def get_session_override():\n            return session\n\n        app.dependency_overrides[get_session] = get_session_override\n\n        client = TestClient(app)  # (2)!\n\n        response = client.post(  # (3)!\n            \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        )\n        app.dependency_overrides.clear()\n        data = response.json()  # (4)!\n\n        assert response.status_code == 200  # (5)!\n        assert data[\"name\"] == \"Deadpond\"  # (6)!\n        assert data[\"secret_name\"] == \"Dive Wilson\"  # (7)!\n        assert data[\"age\"] is None  # (8)!\n        assert data[\"id\"] is not None  # (9)!\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_002.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\n\nfrom .main import app, get_session  # (1)!\n\n\ndef test_create_hero():\n    engine = create_engine(\n        \"sqlite:///testing.db\", connect_args={\"check_same_thread\": False}\n    )\n    SQLModel.metadata.create_all(engine)\n\n    with Session(engine) as session:\n\n        def get_session_override():  # (2)!\n            return session  # (3)!\n\n        app.dependency_overrides[get_session] = get_session_override  # (4)!\n\n        client = TestClient(app)\n\n        response = client.post(\n            \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        )\n        app.dependency_overrides.clear()  # (5)!\n        data = response.json()\n\n        assert response.status_code == 200\n        assert data[\"name\"] == \"Deadpond\"\n        assert data[\"secret_name\"] == \"Dive Wilson\"\n        assert data[\"age\"] is None\n        assert data[\"id\"] is not None\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_003.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\n\nfrom .main import app, get_session  # (1)!\n\n\ndef test_create_hero():\n    engine = create_engine(  # (2)!\n        \"sqlite:///testing.db\", connect_args={\"check_same_thread\": False}\n    )\n    SQLModel.metadata.create_all(engine)  # (3)!\n\n    with Session(engine) as session:  # (4)!\n\n        def get_session_override():\n            return session  # (5)!\n\n        app.dependency_overrides[get_session] = get_session_override  # (4)!\n\n        client = TestClient(app)\n\n        response = client.post(\n            \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        )\n        app.dependency_overrides.clear()\n        data = response.json()\n\n        assert response.status_code == 200\n        assert data[\"name\"] == \"Deadpond\"\n        assert data[\"secret_name\"] == \"Dive Wilson\"\n        assert data[\"age\"] is None\n        assert data[\"id\"] is not None\n    # (6)!\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_004.py",
    "content": "from fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\nfrom sqlmodel.pool import StaticPool  # (1)!\n\nfrom .main import app, get_session\n\n\ndef test_create_hero():\n    engine = create_engine(\n        \"sqlite://\",  # (2)!\n        connect_args={\"check_same_thread\": False},\n        poolclass=StaticPool,  # (3)!\n    )\n    SQLModel.metadata.create_all(engine)\n\n    with Session(engine) as session:\n\n        def get_session_override():\n            return session\n\n        app.dependency_overrides[get_session] = get_session_override\n\n        client = TestClient(app)\n\n        response = client.post(\n            \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        )\n        app.dependency_overrides.clear()\n        data = response.json()\n\n        assert response.status_code == 200\n        assert data[\"name\"] == \"Deadpond\"\n        assert data[\"secret_name\"] == \"Dive Wilson\"\n        assert data[\"age\"] is None\n        assert data[\"id\"] is not None\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_005.py",
    "content": "import pytest  # (1)!\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom .main import app, get_session\n\n\n@pytest.fixture(name=\"session\")  # (2)!\ndef session_fixture():  # (3)!\n    engine = create_engine(\n        \"sqlite://\", connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as session:\n        yield session  # (4)!\n\n\ndef test_create_hero(session: Session):  # (5)!\n    def get_session_override():\n        return session  # (6)!\n\n    app.dependency_overrides[get_session] = get_session_override\n\n    client = TestClient(app)\n\n    response = client.post(\n        \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n    )\n    app.dependency_overrides.clear()\n    data = response.json()\n\n    assert response.status_code == 200\n    assert data[\"name\"] == \"Deadpond\"\n    assert data[\"secret_name\"] == \"Dive Wilson\"\n    assert data[\"age\"] is None\n    assert data[\"id\"] is not None\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_006.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import Session, SQLModel, create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom .main import app, get_session\n\n\n@pytest.fixture(name=\"session\")\ndef session_fixture():\n    engine = create_engine(\n        \"sqlite://\", connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as session:\n        yield session\n\n\n@pytest.fixture(name=\"client\")  # (1)!\ndef client_fixture(session: Session):  # (2)!\n    def get_session_override():  # (3)!\n        return session\n\n    app.dependency_overrides[get_session] = get_session_override  # (4)!\n\n    client = TestClient(app)  # (5)!\n    yield client  # (6)!\n    app.dependency_overrides.clear()  # (7)!\n\n\ndef test_create_hero(client: TestClient):  # (8)!\n    response = client.post(\n        \"/heroes/\", json={\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n    )\n    data = response.json()\n\n    assert response.status_code == 200\n    assert data[\"name\"] == \"Deadpond\"\n    assert data[\"secret_name\"] == \"Dive Wilson\"\n    assert data[\"age\"] is None\n    assert data[\"id\"] is not None\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/delete/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/delete/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n        return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(hero_id: int, hero: HeroUpdate):\n    with Session(engine) as session:\n        db_hero = session.get(Hero, hero_id)\n        if not db_hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        hero_data = hero.model_dump(exclude_unset=True)\n        db_hero.sqlmodel_update(hero_data)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        session.delete(hero)\n        session.commit()\n        return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/limit_and_offset/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n        return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        return hero\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/multiple_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass HeroCreate(SQLModel):\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nclass HeroPublic(SQLModel):\n    id: int\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        return heroes\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        return heroes\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/read_one/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/read_one/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, HTTPException\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        return hero\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/relationships/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/relationships/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass TeamBase(SQLModel):\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Team(TeamBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass TeamCreate(TeamBase):\n    pass\n\n\nclass TeamPublic(TeamBase):\n    id: int\n\n\nclass TeamUpdate(SQLModel):\n    id: int | None = None\n    name: str | None = None\n    headquarters: str | None = None\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n    team_id: int | None = None\n\n\nclass HeroPublicWithTeam(HeroPublic):\n    team: TeamPublic | None = None\n\n\nclass TeamPublicWithHeroes(TeamPublic):\n    heroes: list[HeroPublic] = []\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublicWithTeam)\ndef read_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(\n    *, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate\n):\n    db_hero = session.get(Hero, hero_id)\n    if not db_hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    db_hero.sqlmodel_update(hero_data)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n\n\n@app.post(\"/teams/\", response_model=TeamPublic)\ndef create_team(*, session: Session = Depends(get_session), team: TeamCreate):\n    db_team = Team.model_validate(team)\n    session.add(db_team)\n    session.commit()\n    session.refresh(db_team)\n    return db_team\n\n\n@app.get(\"/teams/\", response_model=list[TeamPublic])\ndef read_teams(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    teams = session.exec(select(Team).offset(offset).limit(limit)).all()\n    return teams\n\n\n@app.get(\"/teams/{team_id}\", response_model=TeamPublicWithHeroes)\ndef read_team(*, team_id: int, session: Session = Depends(get_session)):\n    team = session.get(Team, team_id)\n    if not team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    return team\n\n\n@app.patch(\"/teams/{team_id}\", response_model=TeamPublic)\ndef update_team(\n    *,\n    session: Session = Depends(get_session),\n    team_id: int,\n    team: TeamUpdate,\n):\n    db_team = session.get(Team, team_id)\n    if not db_team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    team_data = team.model_dump(exclude_unset=True)\n    db_team.sqlmodel_update(team_data)\n    session.add(db_team)\n    session.commit()\n    session.refresh(db_team)\n    return db_team\n\n\n@app.delete(\"/teams/{team_id}\")\ndef delete_team(*, session: Session = Depends(get_session), team_id: int):\n    team = session.get(Team, team_id)\n    if not team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    session.delete(team)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/response_model/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/response_model/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=Hero)\ndef create_hero(hero: Hero):\n    with Session(engine) as session:\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        return hero\n\n\n@app.get(\"/heroes/\", response_model=list[Hero])\ndef read_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        return heroes\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/session_with_dependency/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(\n    *, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate\n):\n    db_hero = session.get(Hero, hero_id)\n    if not db_hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    db_hero.sqlmodel_update(hero_data)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/simple_hero_api/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\")\ndef create_hero(hero: Hero):\n    with Session(engine) as session:\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        return hero\n\n\n@app.get(\"/heroes/\")\ndef read_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        return heroes\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/teams/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/teams/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass TeamBase(SQLModel):\n    name: str = Field(index=True)\n    headquarters: str\n\n\nclass Team(TeamBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass TeamCreate(TeamBase):\n    pass\n\n\nclass TeamPublic(TeamBase):\n    id: int\n\n\nclass TeamUpdate(SQLModel):\n    name: str | None = None\n    headquarters: str | None = None\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n    team_id: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(*, session: Session = Depends(get_session), hero: HeroCreate):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(\n    *, session: Session = Depends(get_session), hero_id: int, hero: HeroUpdate\n):\n    db_hero = session.get(Hero, hero_id)\n    if not db_hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    db_hero.sqlmodel_update(hero_data)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(*, session: Session = Depends(get_session), hero_id: int):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n\n\n@app.post(\"/teams/\", response_model=TeamPublic)\ndef create_team(*, session: Session = Depends(get_session), team: TeamCreate):\n    db_team = Team.model_validate(team)\n    session.add(db_team)\n    session.commit()\n    session.refresh(db_team)\n    return db_team\n\n\n@app.get(\"/teams/\", response_model=list[TeamPublic])\ndef read_teams(\n    *,\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    teams = session.exec(select(Team).offset(offset).limit(limit)).all()\n    return teams\n\n\n@app.get(\"/teams/{team_id}\", response_model=TeamPublic)\ndef read_team(*, team_id: int, session: Session = Depends(get_session)):\n    team = session.get(Team, team_id)\n    if not team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    return team\n\n\n@app.patch(\"/teams/{team_id}\", response_model=TeamPublic)\ndef update_team(\n    *,\n    session: Session = Depends(get_session),\n    team_id: int,\n    team: TeamUpdate,\n):\n    db_team = session.get(Team, team_id)\n    if not db_team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    team_data = team.model_dump(exclude_unset=True)\n    db_team.sqlmodel_update(team_data)\n    session.add(db_team)\n    session.commit()\n    session.refresh(db_team)\n    return db_team\n\n\n@app.delete(\"/teams/{team_id}\")\ndef delete_team(*, session: Session = Depends(get_session), team_id: int):\n    team = session.get(Team, team_id)\n    if not team:\n        raise HTTPException(status_code=404, detail=\"Team not found\")\n    session.delete(team)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/update/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/fastapi/update/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n\n\nclass HeroCreate(HeroBase):\n    pass\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    with Session(engine) as session:\n        db_hero = Hero.model_validate(hero)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n        return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(hero_id: int, hero: HeroUpdate):\n    with Session(engine) as session:\n        db_hero = session.get(Hero, hero_id)\n        if not db_hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        hero_data = hero.model_dump(exclude_unset=True)\n        db_hero.sqlmodel_update(hero_data)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n"
  },
  {
    "path": "docs_src/tutorial/fastapi/update/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    hashed_password: str = Field()\n\n\nclass HeroCreate(HeroBase):\n    password: str\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroUpdate(SQLModel):\n    name: str | None = None\n    secret_name: str | None = None\n    age: int | None = None\n    password: str | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, echo=True, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef hash_password(password: str) -> str:\n    # Use something like passlib here\n    return f\"not really hashed {password} hehehe\"\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate):\n    hashed_password = hash_password(hero.password)\n    with Session(engine) as session:\n        extra_data = {\"hashed_password\": hashed_password}\n        db_hero = Hero.model_validate(hero, update=extra_data)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n        return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int):\n    with Session(engine) as session:\n        hero = session.get(Hero, hero_id)\n        if not hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(hero_id: int, hero: HeroUpdate):\n    with Session(engine) as session:\n        db_hero = session.get(Hero, hero_id)\n        if not db_hero:\n            raise HTTPException(status_code=404, detail=\"Hero not found\")\n        hero_data = hero.model_dump(exclude_unset=True)\n        extra_data = {}\n        if \"password\" in hero_data:\n            password = hero_data[\"password\"]\n            hashed_password = hash_password(password)\n            extra_data[\"hashed_password\"] = hashed_password\n        db_hero.sqlmodel_update(hero_data, update=extra_data)\n        session.add(db_hero)\n        session.commit()\n        session.refresh(db_hero)\n        return db_hero\n"
  },
  {
    "path": "docs_src/tutorial/indexes/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/indexes/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Deadpond\")\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/indexes/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age <= 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/insert/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/insert/annotations/en/tutorial003.md",
    "content": "1. We use a function `create_heroes()` to put this logic together.\n\n2. Create each of the objects/instances of the `Hero` model.\n\n    Each of them represents the data for one row.\n\n3. Use a `with` block to create a `Session` using the `engine`.\n\n    The new **sesion** will be assigned to the variable `session`.\n\n    And it will be automatically closed when the `with` block is finished.\n\n4. Add each of the objects/instances to the **session**.\n\n    Each of these objects represents a row in the database.\n\n    They are all waiting there in the session to be saved.\n\n5. **Commit** the changes to the database.\n\n    This will actually send the data to the database.\n\n    It will start a transaction automatically and save all the data in a single batch.\n\n6. By this point, after the `with` block is finished, the **session** is automatically closed.\n\n7. We have a `main()` function with all the code that should be executed when the program is called as a **script from the console**.\n\n    That way we can add more code later to this function.\n\n    We then put this function `main()` in the main block below.\n\n    And as it is a single function, other Python files could **import it** and call it directly.\n\n8. In this `main()` function, we are also creating the database and the tables.\n\n    In the previous version, this function was called directly in the main block.\n\n    But now it is just called in the `main()` function.\n\n9. And now we are also creating the heroes in this `main()` function.\n\n10. We still have a main block to execute some code when the program is run as a script from the command line, like:\n\n    <div class=\"termy\">\n\n    ```console\n    $ python app.py\n\n    // Do whatever is in the main block 🚀\n    ```\n\n    </div>\n\n11. There's a single `main()` function now that contains all the code that should be executed when running the program from the console.\n\n    So this is all we need to have in the main block. Just call the `main()` function.\n"
  },
  {
    "path": "docs_src/tutorial/insert/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    session = Session(engine)\n\n    session.add(hero_1)\n    session.add(hero_2)\n    session.add(hero_3)\n\n    session.commit()\n\n    session.close()\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/insert/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/insert/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():  # (1)!\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")  # (2)!\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:  # (3)!\n        session.add(hero_1)  # (4)!\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()  # (5)!\n    # (6)!\n\n\ndef main():  # (7)!\n    create_db_and_tables()  # (8)!\n    create_heroes()  # (9)!\n\n\nif __name__ == \"__main__\":  # (10)!\n    main()  # (11)!\n"
  },
  {
    "path": "docs_src/tutorial/many_to_many/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/many_to_many/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine\n\n\nclass HeroTeamLink(SQLModel, table=True):\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\", primary_key=True)\n    hero_id: int | None = Field(default=None, foreign_key=\"hero.id\", primary_key=True)\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"teams\", link_model=HeroTeamLink)\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    teams: list[Team] = Relationship(back_populates=\"heroes\", link_model=HeroTeamLink)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\",\n            secret_name=\"Dive Wilson\",\n            teams=[team_z_force, team_preventers],\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            teams=[team_preventers],\n        )\n        hero_spider_boy = Hero(\n            name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\", teams=[team_preventers]\n        )\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Deadpond:\", hero_deadpond)\n        print(\"Deadpond teams:\", hero_deadpond.teams)\n        print(\"Rusty-Man:\", hero_rusty_man)\n        print(\"Rusty-Man Teams:\", hero_rusty_man.teams)\n        print(\"Spider-Boy:\", hero_spider_boy)\n        print(\"Spider-Boy Teams:\", hero_spider_boy.teams)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/many_to_many/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass HeroTeamLink(SQLModel, table=True):\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\", primary_key=True)\n    hero_id: int | None = Field(default=None, foreign_key=\"hero.id\", primary_key=True)\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"teams\", link_model=HeroTeamLink)\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    teams: list[Team] = Relationship(back_populates=\"heroes\", link_model=HeroTeamLink)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\",\n            secret_name=\"Dive Wilson\",\n            teams=[team_z_force, team_preventers],\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n            teams=[team_preventers],\n        )\n        hero_spider_boy = Hero(\n            name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\", teams=[team_preventers]\n        )\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Deadpond:\", hero_deadpond)\n        print(\"Deadpond teams:\", hero_deadpond.teams)\n        print(\"Rusty-Man:\", hero_rusty_man)\n        print(\"Rusty-Man Teams:\", hero_rusty_man.teams)\n        print(\"Spider-Boy:\", hero_spider_boy)\n        print(\"Spider-Boy Teams:\", hero_spider_boy.teams)\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        hero_spider_boy = session.exec(\n            select(Hero).where(Hero.name == \"Spider-Boy\")\n        ).one()\n        team_z_force = session.exec(select(Team).where(Team.name == \"Z-Force\")).one()\n\n        team_z_force.heroes.append(hero_spider_boy)\n        session.add(team_z_force)\n        session.commit()\n\n        print(\"Updated Spider-Boy's Teams:\", hero_spider_boy.teams)\n        print(\"Z-Force heroes:\", team_z_force.heroes)\n\n        hero_spider_boy.teams.remove(team_z_force)\n        session.add(team_z_force)\n        session.commit()\n\n        print(\"Reverted Z-Force's heroes:\", team_z_force.heroes)\n        print(\"Reverted Spider-Boy's teams:\", hero_spider_boy.teams)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/many_to_many/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass HeroTeamLink(SQLModel, table=True):\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\", primary_key=True)\n    hero_id: int | None = Field(default=None, foreign_key=\"hero.id\", primary_key=True)\n    is_training: bool = False\n\n    team: \"Team\" = Relationship(back_populates=\"hero_links\")\n    hero: \"Hero\" = Relationship(back_populates=\"team_links\")\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    hero_links: list[HeroTeamLink] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_links: list[HeroTeamLink] = Relationship(back_populates=\"hero\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\",\n            secret_name=\"Dive Wilson\",\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\",\n            secret_name=\"Tommy Sharp\",\n            age=48,\n        )\n        hero_spider_boy = Hero(\n            name=\"Spider-Boy\",\n            secret_name=\"Pedro Parqueador\",\n        )\n        deadpond_team_z_link = HeroTeamLink(team=team_z_force, hero=hero_deadpond)\n        deadpond_preventers_link = HeroTeamLink(\n            team=team_preventers, hero=hero_deadpond, is_training=True\n        )\n        spider_boy_preventers_link = HeroTeamLink(\n            team=team_preventers, hero=hero_spider_boy, is_training=True\n        )\n        rusty_man_preventers_link = HeroTeamLink(\n            team=team_preventers, hero=hero_rusty_man\n        )\n\n        session.add(deadpond_team_z_link)\n        session.add(deadpond_preventers_link)\n        session.add(spider_boy_preventers_link)\n        session.add(rusty_man_preventers_link)\n        session.commit()\n\n        for link in team_z_force.hero_links:\n            print(\"Z-Force hero:\", link.hero, \"is training:\", link.is_training)\n\n        for link in team_preventers.hero_links:\n            print(\"Preventers hero:\", link.hero, \"is training:\", link.is_training)\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        hero_spider_boy = session.exec(\n            select(Hero).where(Hero.name == \"Spider-Boy\")\n        ).one()\n        team_z_force = session.exec(select(Team).where(Team.name == \"Z-Force\")).one()\n\n        spider_boy_z_force_link = HeroTeamLink(\n            team=team_z_force, hero=hero_spider_boy, is_training=True\n        )\n        team_z_force.hero_links.append(spider_boy_z_force_link)\n        session.add(team_z_force)\n        session.commit()\n\n        print(\"Updated Spider-Boy's Teams:\", hero_spider_boy.team_links)\n        print(\"Z-Force heroes:\", team_z_force.hero_links)\n\n        for link in hero_spider_boy.team_links:\n            if link.team.name == \"Preventers\":\n                link.is_training = False\n\n        session.add(hero_spider_boy)\n        session.commit()\n\n        for link in hero_spider_boy.team_links:\n            print(\"Spider-Boy team:\", link.team, \"is training:\", link.is_training)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/offset_and_limit/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/offset_and_limit/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).limit(3)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/offset_and_limit/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).offset(3).limit(3)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/offset_and_limit/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).offset(6).limit(3)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/offset_and_limit/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age > 32).offset(1).limit(2)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/one/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age <= 35)\n        results = session.exec(statement)\n        hero = results.first()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age < 25)\n        results = session.exec(statement)\n        hero = results.first()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Deadpond\")\n        results = session.exec(statement)\n        hero = results.one()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age <= 35)\n        results = session.exec(statement)\n        hero = results.one()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial005_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age < 25)\n        results = session.exec(statement)\n        hero = results.one()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial006_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        hero = session.exec(select(Hero).where(Hero.name == \"Deadpond\")).one()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial007_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.id == 1)\n        results = session.exec(statement)\n        hero = results.first()\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial008_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        hero = session.get(Hero, 1)\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/one/tutorial009_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        hero = session.get(Hero, 9001)\n        print(\"Hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/back_populates/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/back_populates/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship()\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship()\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n        hero_tarantula = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n        hero_dr_weird = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n        hero_cap = Hero(\n            name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93\n        )\n\n        team_preventers.heroes.append(hero_tarantula)\n        team_preventers.heroes.append(hero_dr_weird)\n        team_preventers.heroes.append(hero_cap)\n        session.add(team_preventers)\n        session.commit()\n        session.refresh(hero_tarantula)\n        session.refresh(hero_dr_weird)\n        session.refresh(hero_cap)\n        print(\"Preventers new hero:\", hero_tarantula)\n        print(\"Preventers new hero:\", hero_dr_weird)\n        print(\"Preventers new hero:\", hero_cap)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Preventers\")\n        result = session.exec(statement)\n        team_preventers = result.one()\n\n        print(\"Preventers heroes:\", team_preventers.heroes)\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        hero_spider_boy = session.exec(\n            select(Hero).where(Hero.name == \"Spider-Boy\")\n        ).one()\n\n        preventers_team = session.exec(\n            select(Team).where(Team.name == \"Preventers\")\n        ).one()\n\n        print(\"Hero Spider-Boy:\", hero_spider_boy)\n        print(\"Preventers Team:\", preventers_team)\n        print(\"Preventers Team Heroes:\", preventers_team.heroes)\n\n        hero_spider_boy.team = None\n\n        print(\"Spider-Boy without team:\", hero_spider_boy)\n\n        print(\"Preventers Team Heroes again:\", preventers_team.heroes)\n\n        session.add(hero_spider_boy)\n        session.commit()\n        print(\"After committing\")\n\n        session.refresh(hero_spider_boy)\n        print(\"Spider-Boy after commit:\", hero_spider_boy)\n\n        print(\"Preventers Team Heroes after commit:\", preventers_team.heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/back_populates/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n        hero_tarantula = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n        hero_dr_weird = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n        hero_cap = Hero(\n            name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93\n        )\n\n        team_preventers.heroes.append(hero_tarantula)\n        team_preventers.heroes.append(hero_dr_weird)\n        team_preventers.heroes.append(hero_cap)\n        session.add(team_preventers)\n        session.commit()\n        session.refresh(hero_tarantula)\n        session.refresh(hero_dr_weird)\n        session.refresh(hero_cap)\n        print(\"Preventers new hero:\", hero_tarantula)\n        print(\"Preventers new hero:\", hero_dr_weird)\n        print(\"Preventers new hero:\", hero_cap)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Preventers\")\n        result = session.exec(statement)\n        team_preventers = result.one()\n\n        print(\"Preventers heroes:\", team_preventers.heroes)\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        hero_spider_boy = session.exec(\n            select(Hero).where(Hero.name == \"Spider-Boy\")\n        ).one()\n\n        preventers_team = session.exec(\n            select(Team).where(Team.name == \"Preventers\")\n        ).one()\n\n        print(\"Hero Spider-Boy:\", hero_spider_boy)\n        print(\"Preventers Team:\", preventers_team)\n        print(\"Preventers Team Heroes:\", preventers_team.heroes)\n\n        hero_spider_boy.team = None\n\n        print(\"Spider-Boy without team:\", hero_spider_boy)\n\n        print(\"Preventers Team Heroes again:\", preventers_team.heroes)\n\n        session.add(hero_spider_boy)\n        session.commit()\n        print(\"After committing\")\n\n        session.refresh(hero_spider_boy)\n        print(\"Spider-Boy after commit:\", hero_spider_boy)\n\n        print(\"Preventers Team Heroes after commit:\", preventers_team.heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/back_populates/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Relationship, SQLModel, create_engine\n\n\nclass Weapon(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n\n    hero: \"Hero\" = Relationship(back_populates=\"weapon\")\n\n\nclass Power(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n\n    hero_id: int = Field(foreign_key=\"hero.id\")\n    hero: \"Hero\" = Relationship(back_populates=\"powers\")\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n    weapon_id: int | None = Field(default=None, foreign_key=\"weapon.id\")\n    weapon: Weapon | None = Relationship(back_populates=\"hero\")\n\n    powers: list[Power] = Relationship(back_populates=\"hero\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef main():\n    create_db_and_tables()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\", cascade_delete=True)\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\", ondelete=\"CASCADE\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n\ndef delete_team():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        session.delete(team)\n        session.commit()\n        print(\"Deleted team:\", team)\n\n\ndef select_deleted_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Black Lion\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Black Lion not found:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Princess Sure-E\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Princess Sure-E not found:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    delete_team()\n    select_deleted_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(\n        default=None, foreign_key=\"team.id\", ondelete=\"SET NULL\"\n    )\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n\ndef delete_team():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        session.delete(team)\n        session.commit()\n        print(\"Deleted team:\", team)\n\n\ndef select_deleted_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Black Lion\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Black Lion has no team:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Princess Sure-E\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Princess Sure-E has no team:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    delete_team()\n    select_deleted_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select, text\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\", passive_deletes=\"all\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(\n        default=None, foreign_key=\"team.id\", ondelete=\"SET NULL\"\n    )\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n    with engine.connect() as connection:\n        connection.execute(text(\"PRAGMA foreign_keys=ON\"))  # for SQLite only\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n\ndef delete_team():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        session.delete(team)\n        session.commit()\n        print(\"Deleted team:\", team)\n\n\ndef select_deleted_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Black Lion\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Black Lion has no team:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Princess Sure-E\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Princess Sure-E has no team:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    delete_team()\n    select_deleted_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select, text\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\", passive_deletes=\"all\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(\n        default=None, foreign_key=\"team.id\", ondelete=\"RESTRICT\"\n    )\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n    with engine.connect() as connection:\n        connection.execute(text(\"PRAGMA foreign_keys=ON\"))  # for SQLite only\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n\ndef delete_team():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        session.delete(team)\n        session.commit()\n        print(\"Deleted team:\", team)\n\n\ndef select_deleted_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Black Lion\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Black Lion has no team:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Princess Sure-E\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Princess Sure-E has no team:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    delete_team()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/cascade_delete_relationships/tutorial005_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select, text\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\", passive_deletes=\"all\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(\n        default=None, foreign_key=\"team.id\", ondelete=\"RESTRICT\"\n    )\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n    with engine.connect() as connection:\n        connection.execute(text(\"PRAGMA foreign_keys=ON\"))  # for SQLite only\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n\ndef remove_team_heroes():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        team.heroes.clear()\n        session.add(team)\n        session.commit()\n        session.refresh(team)\n        print(\"Team with removed heroes:\", team)\n\n\ndef delete_team():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Wakaland\")\n        team = session.exec(statement).one()\n        session.delete(team)\n        session.commit()\n        print(\"Deleted team:\", team)\n\n\ndef select_deleted_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Black Lion\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Black Lion has no team:\", hero)\n\n        statement = select(Hero).where(Hero.name == \"Princess Sure-E\")\n        result = session.exec(statement)\n        hero = result.first()\n        print(\"Princess Sure-E has no team:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    remove_team_heroes()\n    delete_team()\n    select_deleted_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/create_and_update_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/create_and_update_relationships/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n        hero_tarantula = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n        hero_dr_weird = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n        hero_cap = Hero(\n            name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93\n        )\n\n        team_preventers.heroes.append(hero_tarantula)\n        team_preventers.heroes.append(hero_dr_weird)\n        team_preventers.heroes.append(hero_cap)\n        session.add(team_preventers)\n        session.commit()\n        session.refresh(hero_tarantula)\n        session.refresh(hero_dr_weird)\n        session.refresh(hero_cap)\n        print(\"Preventers new hero:\", hero_tarantula)\n        print(\"Preventers new hero:\", hero_dr_weird)\n        print(\"Preventers new hero:\", hero_cap)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/define_relationship_attributes/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/read_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/read_relationships/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n        hero_tarantula = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n        hero_dr_weird = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n        hero_cap = Hero(\n            name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93\n        )\n\n        team_preventers.heroes.append(hero_tarantula)\n        team_preventers.heroes.append(hero_dr_weird)\n        team_preventers.heroes.append(hero_cap)\n        session.add(team_preventers)\n        session.commit()\n        session.refresh(hero_tarantula)\n        session.refresh(hero_dr_weird)\n        session.refresh(hero_cap)\n        print(\"Preventers new hero:\", hero_tarantula)\n        print(\"Preventers new hero:\", hero_dr_weird)\n        print(\"Preventers new hero:\", hero_cap)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        result = session.exec(statement)\n        hero_spider_boy = result.one()\n\n        statement = select(Team).where(Team.id == hero_spider_boy.team_id)\n        result = session.exec(statement)\n        team = result.first()\n        print(\"Spider-Boy's team:\", team)\n\n        print(\"Spider-Boy's team again:\", hero_spider_boy.team)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/relationship_attributes/read_relationships/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\n\n\nclass Team(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    headquarters: str\n\n    heroes: list[\"Hero\"] = Relationship(back_populates=\"team\")\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n    team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n    team: Team | None = Relationship(back_populates=\"heroes\")\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    with Session(engine) as session:\n        team_preventers = Team(name=\"Preventers\", headquarters=\"Sharp Tower\")\n        team_z_force = Team(name=\"Z-Force\", headquarters=\"Sister Margaret's Bar\")\n\n        hero_deadpond = Hero(\n            name=\"Deadpond\", secret_name=\"Dive Wilson\", team=team_z_force\n        )\n        hero_rusty_man = Hero(\n            name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48, team=team_preventers\n        )\n        hero_spider_boy = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n        session.add(hero_deadpond)\n        session.add(hero_rusty_man)\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_deadpond)\n        session.refresh(hero_rusty_man)\n        session.refresh(hero_spider_boy)\n\n        print(\"Created hero:\", hero_deadpond)\n        print(\"Created hero:\", hero_rusty_man)\n        print(\"Created hero:\", hero_spider_boy)\n\n        hero_spider_boy.team = team_preventers\n        session.add(hero_spider_boy)\n        session.commit()\n        session.refresh(hero_spider_boy)\n        print(\"Updated hero:\", hero_spider_boy)\n\n        hero_black_lion = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n        hero_sure_e = Hero(name=\"Princess Sure-E\", secret_name=\"Sure-E\")\n        team_wakaland = Team(\n            name=\"Wakaland\",\n            headquarters=\"Wakaland Capital City\",\n            heroes=[hero_black_lion, hero_sure_e],\n        )\n        session.add(team_wakaland)\n        session.commit()\n        session.refresh(team_wakaland)\n        print(\"Team Wakaland:\", team_wakaland)\n\n        hero_tarantula = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n        hero_dr_weird = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n        hero_cap = Hero(\n            name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93\n        )\n\n        team_preventers.heroes.append(hero_tarantula)\n        team_preventers.heroes.append(hero_dr_weird)\n        team_preventers.heroes.append(hero_cap)\n        session.add(team_preventers)\n        session.commit()\n        session.refresh(hero_tarantula)\n        session.refresh(hero_dr_weird)\n        session.refresh(hero_cap)\n        print(\"Preventers new hero:\", hero_tarantula)\n        print(\"Preventers new hero:\", hero_dr_weird)\n        print(\"Preventers new hero:\", hero_cap)\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Team).where(Team.name == \"Preventers\")\n        result = session.exec(statement)\n        team_preventers = result.one()\n\n        print(\"Preventers heroes:\", team_preventers.heroes)\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        result = session.exec(statement)\n        hero_spider_boy = result.one()\n\n        hero_spider_boy.team = None\n        session.add(hero_spider_boy)\n        session.commit()\n\n        session.refresh(hero_spider_boy)\n        print(\"Spider-Boy without team:\", hero_spider_boy)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/select/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/select/annotations/en/tutorial002.md",
    "content": "1. Import from `sqlmodel` everything we will use, including the new `select()` function.\n\n2. Create the `Hero` class model, representing the `hero` table.\n\n3. Create the **engine**, we should use a single one shared by all the application code, and that's what we are doing here.\n\n4. Create all the tables for the models registered in `SQLModel.metadata`.\n\n    This also creates the database if it doesn't exist already.\n\n5. Create each one of the `Hero` objects.\n\n    You might not have this in your version if you had already created the data in the database.\n\n6. Create a new **session** and use it to `add` the heroes to the database, and then `commit` the changes.\n\n7. Create a new **session** to query data.\n\n    /// tip\n\n    Notice that this is a new **session** independent from the one in the other function above.\n\n    But it still uses the same **engine**. We still have one engine for the whole application.\n\n    ///\n\n8. Use the `select()` function to create a statement selecting all the `Hero` objects.\n\n    This selects all the rows in the `hero` table.\n\n9. Use `session.exec(statement)` to make the **session** use the **engine** to execute the internal SQL statement.\n\n    This will go to the database, execute that SQL, and get the results back.\n\n    It returns a special iterable object that we put in the variable `results`.\n\n    This generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    INFO Engine [no key 0.00032s] ()\n    ```\n\n10. Iterate for each `Hero` object in the `results`.\n\n11. Print each `hero`.\n\n    The 3 iterations in the `for` loop will generate this output:\n\n    ```\n    id=1 name='Deadpond' age=None secret_name='Dive Wilson'\n    id=2 name='Spider-Boy' age=None secret_name='Pedro Parqueador'\n    id=3 name='Rusty-Man' age=48 secret_name='Tommy Sharp'\n    ```\n\n12. At this point, after the `with` block, the **session** is closed.\n\n    This generates the output:\n\n    ```\n    INFO Engine ROLLBACK\n    ```\n\n13. Add this function `select_heroes()` to the `main()` function so that it is called when we run this program from the command line.\n"
  },
  {
    "path": "docs_src/tutorial/select/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/select/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select  # (1)!\n\n\nclass Hero(SQLModel, table=True):  # (2)!\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)  # (3)!\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)  # (4)!\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")  # (5)!\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:  # (6)!\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:  # (7)!\n        statement = select(Hero)  # (8)!\n        results = session.exec(statement)  # (9)!\n        for hero in results:  # (10)!\n            print(hero)  # (11)!\n    # (12)!\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()  # (13)!\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/select/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/select/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        print(heroes)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/update/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/update/annotations/en/tutorial002.md",
    "content": "1. Select the hero we will work with.\n\n2. Execute the query with the select statement object.\n\n    This generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.name = ?\n    INFO Engine [no key 0.00017s] ('Spider-Boy',)\n    ```\n\n3. Get one hero object, expecting exactly one.\n\n    /// tip\n\n    This ensures there's no more than one, and that there's exactly one, not `None`.\n\n    This would never return `None`, instead it would raise an exception.\n\n    ///\n\n4. Print the hero object.\n\n    This generates the output:\n\n    ```\n    Hero: name='Spider-Boy' secret_name='Pedro Parqueador' age=None id=2\n    ```\n\n5. Set the hero's age field to the new value `16`.\n\n    Now the `hero` object in memory has a different value for the age, but it is still not saved to the database.\n\n6. Add the hero to the session.\n\n    This puts it in that temporary place in the session before committing.\n\n    But it's still not saved in the database yet.\n\n7. Commit the session.\n\n    This saves the updated hero to the database.\n\n    And this generates the output:\n\n    ```\n    INFO Engine UPDATE hero SET age=? WHERE hero.id = ?\n    INFO Engine [generated in 0.00017s] (16, 2)\n    INFO Engine COMMIT\n    ```\n\n8. Refresh the hero object to have the recent data, including the age we just committed.\n\n    This generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [generated in 0.00018s] (2,)\n    ```\n\n9. Print the updated hero object.\n\n    This generates the output:\n\n    ```\n    Updated hero: name='Spider-Boy' secret_name='Pedro Parqueador' age=16 id=2\n    ```\n"
  },
  {
    "path": "docs_src/tutorial/update/annotations/en/tutorial004.md",
    "content": "1. Select the hero `Spider-Boy`.\n\n2. Execute the select statement.\n\n    This generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.name = ?\n    INFO Engine [no key 0.00018s] ('Spider-Boy',)\n    ```\n\n3. Get one hero object, the only one that should be there for **Spider-Boy**.\n\n4. Print this hero.\n\n    This generates the output:\n\n    ```\n    Hero 1: name='Spider-Boy' secret_name='Pedro Parqueador' age=None id=2\n    ```\n\n5. Select another hero.\n\n6. Execute the select statement.\n\n    This generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.name = ?\n    INFO Engine [no key 0.00020s] ('Captain North America',)\n    ```\n\n    /// tip\n\n    See the `BEGIN` at the top?\n\n    This is SQLAlchemy automatically starting a transaction for us.\n\n    This way, we could revert the last changes (if there were some) if we wanted to, even if the SQL to create them was already sent to the database.\n\n    ///\n\n7. Get one hero object for this new query.\n\n    The only one that should be there for **Captain North America**.\n\n8. Print this second hero.\n\n    This generates the output:\n\n    ```\n    Hero 2: name='Captain North America' secret_name='Esteban Rogelios' age=93 id=7\n    ```\n\n9. Update the age for the first hero.\n\n    Set the value of the attribute `age` to `16`.\n\n    This updates the hero object in memory, but not yet in the database.\n\n10. Update the name of the first hero.\n\n    Now the name of the hero will not be `\"Spider-Boy\"` but `\"Spider-Youngster\"`.\n\n    Also, this updates the object in memory, but not yet in the database.\n\n11. Add this first hero to the session.\n\n    This puts it in the temporary space in the **session** before committing it to the database.\n\n    It is not saved yet.\n\n12. Update the name of the second hero.\n\n    Now the hero has a bit more precision in the name. 😜\n\n    This updates the object in memory, but not yet in the database.\n\n13. Update the age of the second hero.\n\n    This updates the object in memory, but not yet in the database.\n\n14. Add the second hero to the session.\n\n    This puts it in the temporary space in the **session** before committing it to the database.\n\n15. Commit all the changes tracked in the session.\n\n    This commits everything in one single batch.\n\n    This generates the output:\n\n    ```\n    INFO Engine UPDATE hero SET name=?, age=? WHERE hero.id = ?\n    INFO Engine [generated in 0.00028s] (('Spider-Youngster', 16, 2), ('Captain North America Except Canada', 110, 7))\n    INFO Engine COMMIT\n    ```\n\n    /// tip\n\n    See how SQLAlchemy (that powers SQLModel) optimizes the SQL to do as much work as possible in a single batch.\n\n    Here it updates both heroes in a single SQL query.\n\n    ///\n\n16. Refresh the first hero.\n\n    This generates the output:\n\n    ```\n    INFO Engine BEGIN (implicit)\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [generated in 0.00023s] (2,)\n    ```\n\n    /// tip\n\n    Because we just committed a SQL transaction with `COMMIT`, SQLAlchemy will automatically start a new transaction with `BEGIN`.\n\n    ///\n\n17. Refresh the second hero.\n\n    This generates the output:\n\n    ```\n    INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age\n    FROM hero\n    WHERE hero.id = ?\n    INFO Engine [cached since 0.001709s ago] (7,)\n    ```\n\n    /// tip\n\n    SQLAlchemy is still using the previous transaction, so it doesn't have to create a new one.\n\n    ///\n\n18. Print the first hero, now updated.\n\n    This generates the output:\n\n    ```\n    Updated hero 1: name='Spider-Youngster' secret_name='Pedro Parqueador' age=16 id=2\n    ```\n\n19. Print the second hero, now updated.\n\n    This generates the output:\n\n    ```\n    Updated hero 2: name='Captain North America Except Canada' secret_name='Esteban Rogelios' age=110 id=7\n    ```\n\n20. Here is the end of the `with` block statement, so the session can execute its terminating code.\n\n    The session will `ROLLBACK` (undo) any possible changes in the last transaction that were not committed.\n\n    This generates the output:\n\n    ```\n    INFO Engine ROLLBACK\n    ```\n"
  },
  {
    "path": "docs_src/tutorial/update/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        results = session.exec(statement)\n        hero = results.one()\n        print(\"Hero:\", hero)\n\n        hero.age = 16\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n        print(\"Updated hero:\", hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/update/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")  # (1)!\n        results = session.exec(statement)  # (2)!\n        hero = results.one()  # (3)!\n        print(\"Hero:\", hero)  # (4)!\n\n        hero.age = 16  # (5)!\n        session.add(hero)  # (6)!\n        session.commit()  # (7)!\n        session.refresh(hero)  # (8)!\n        print(\"Updated hero:\", hero)  # (9)!\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/update/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")\n        results = session.exec(statement)\n        hero_1 = results.one()\n        print(\"Hero 1:\", hero_1)\n\n        statement = select(Hero).where(Hero.name == \"Captain North America\")\n        results = session.exec(statement)\n        hero_2 = results.one()\n        print(\"Hero 2:\", hero_2)\n\n        hero_1.age = 16\n        hero_1.name = \"Spider-Youngster\"\n        session.add(hero_1)\n\n        hero_2.name = \"Captain North America Except Canada\"\n        hero_2.age = 110\n        session.add(hero_2)\n\n        session.commit()\n        session.refresh(hero_1)\n        session.refresh(hero_2)\n\n        print(\"Updated hero 1:\", hero_1)\n        print(\"Updated hero 2:\", hero_2)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/update/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    secret_name: str\n    age: int | None = Field(default=None, index=True)\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef update_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Spider-Boy\")  # (1)!\n        results = session.exec(statement)  # (2)!\n        hero_1 = results.one()  # (3)!\n        print(\"Hero 1:\", hero_1)  # (4)!\n\n        statement = select(Hero).where(Hero.name == \"Captain North America\")  # (5)!\n        results = session.exec(statement)  # (6)!\n        hero_2 = results.one()  # (7)!\n        print(\"Hero 2:\", hero_2)  # (8)!\n\n        hero_1.age = 16  # (9)!\n        hero_1.name = \"Spider-Youngster\"  # (10)!\n        session.add(hero_1)  # (11)!\n\n        hero_2.name = \"Captain North America Except Canada\"  # (12)!\n        hero_2.age = 110  # (13)!\n        session.add(hero_2)  # (14)!\n\n        session.commit()  # (15)!\n        session.refresh(hero_1)  # (16)!\n        session.refresh(hero_2)  # (17)!\n\n        print(\"Updated hero 1:\", hero_1)  # (18)!\n        print(\"Updated hero 2:\", hero_2)  # (19)!\n    # (20)!\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    update_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/tutorial/where/tutorial001_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name == \"Deadpond\")\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial002_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.name != \"Deadpond\")\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial003_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age > 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial004_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age >= 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial005_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age < 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial006_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age <= 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial006b_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, col, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(col(Hero.name).in_([\"Deadpond\", \"Ratman\"]))\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial006b_py39.py",
    "content": "from typing import Optional\n\nfrom sqlmodel import Field, Session, SQLModel, col, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: Optional[int] = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: Optional[int] = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(col(Hero.name).in_([\"Deadpond\", \"Ratman\"]))\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial007_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age >= 35).where(Hero.age < 40)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial008_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age >= 35, Hero.age < 40)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial009_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, or_, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(or_(Hero.age <= 35, Hero.age > 90))\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "docs_src/tutorial/where/tutorial011_py310.py",
    "content": "from sqlmodel import Field, Session, SQLModel, col, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: int | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nengine = create_engine(sqlite_url, echo=True)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\")\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n    hero_4 = Hero(name=\"Tarantula\", secret_name=\"Natalia Roman-on\", age=32)\n    hero_5 = Hero(name=\"Black Lion\", secret_name=\"Trevor Challa\", age=35)\n    hero_6 = Hero(name=\"Dr. Weird\", secret_name=\"Steve Weird\", age=36)\n    hero_7 = Hero(name=\"Captain North America\", secret_name=\"Esteban Rogelios\", age=93)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n        session.add(hero_4)\n        session.add(hero_5)\n        session.add(hero_6)\n        session.add(hero_7)\n\n        session.commit()\n\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(col(Hero.age) >= 35)\n        results = session.exec(statement)\n        for hero in results:\n            print(hero)\n\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "mkdocs.env.yml",
    "content": "# Define this here and not in the main mkdocs.yml file because that one could be auto\n# updated and written, and the script would remove the env var\nmarkdown_extensions:\n  pymdownx.highlight:\n    linenums: !ENV [LINENUMS, false]\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "INHERIT: ./mkdocs.env.yml\nsite_name: SQLModel\nsite_description: SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.\nsite_url: https://sqlmodel.tiangolo.com/\ntheme:\n  name: material\n  custom_dir: docs/overrides\n  palette:\n  - media: \"(prefers-color-scheme)\"\n    toggle:\n      icon: material/lightbulb-auto\n      name: Switch to light mode\n  - media: '(prefers-color-scheme: light)'\n    scheme: default\n    primary: deep purple\n    accent: amber\n    toggle:\n      icon: material/lightbulb\n      name: Switch to dark mode\n  - media: '(prefers-color-scheme: dark)'\n    scheme: slate\n    primary: deep purple\n    accent: amber\n    toggle:\n      icon: material/lightbulb-outline\n      name: Switch to system preference\n  features:\n  - content.code.annotate\n  - content.code.copy\n  # - content.code.select\n  - content.footnote.tooltips\n  - content.tabs.link\n  - content.tooltips\n  - navigation.footer\n  - navigation.indexes\n  - navigation.instant\n  - navigation.instant.prefetch\n  # - navigation.instant.preview\n  - navigation.instant.progress\n  - navigation.path\n  - navigation.tabs\n  - navigation.tabs.sticky\n  - navigation.top\n  - navigation.tracking\n  - search.highlight\n  - search.share\n  - search.suggest\n  - toc.follow\n\n  icon:\n    repo: fontawesome/brands/github-alt\n  logo: img/icon-white.svg\n  favicon: img/favicon.png\n  language: en\nrepo_name: fastapi/sqlmodel\nrepo_url: https://github.com/fastapi/sqlmodel\nplugins:\n  # Material for MkDocs\n  search:\n  social:\n  typeset:\n  # Other plugins\n  macros:\n    include_yaml:\n    - sponsors: data/sponsors.yml\n    - members: data/members.yml\n\nnav:\n  - SQLModel: index.md\n  - features.md\n  - Learn:\n    - learn/index.md\n    - databases.md\n    - db-to-code.md\n    - environment-variables.md\n    - virtual-environments.md\n    - install.md\n    - Tutorial - User Guide:\n      - tutorial/index.md\n      - tutorial/create-db-and-table-with-db-browser.md\n      - tutorial/create-db-and-table.md\n      - tutorial/insert.md\n      - tutorial/automatic-id-none-refresh.md\n      - tutorial/select.md\n      - tutorial/where.md\n      - tutorial/indexes.md\n      - tutorial/one.md\n      - tutorial/limit-and-offset.md\n      - tutorial/update.md\n      - tutorial/delete.md\n      - Connect Tables - JOIN:\n        - tutorial/connect/index.md\n        - tutorial/connect/create-connected-tables.md\n        - tutorial/connect/create-connected-rows.md\n        - tutorial/connect/read-connected-data.md\n        - tutorial/connect/update-data-connections.md\n        - tutorial/connect/remove-data-connections.md\n      - Relationship Attributes:\n        - tutorial/relationship-attributes/index.md\n        - tutorial/relationship-attributes/define-relationships-attributes.md\n        - tutorial/relationship-attributes/create-and-update-relationships.md\n        - tutorial/relationship-attributes/read-relationships.md\n        - tutorial/relationship-attributes/remove-relationships.md\n        - tutorial/relationship-attributes/back-populates.md\n        - tutorial/relationship-attributes/cascade-delete-relationships.md\n        - tutorial/relationship-attributes/type-annotation-strings.md\n      - Many to Many:\n        - tutorial/many-to-many/index.md\n        - tutorial/many-to-many/create-models-with-link.md\n        - tutorial/many-to-many/create-data.md\n        - tutorial/many-to-many/update-remove-relationships.md\n        - tutorial/many-to-many/link-with-extra-fields.md\n      - tutorial/code-structure.md\n      - FastAPI and Pydantic:\n        - tutorial/fastapi/index.md\n        - tutorial/fastapi/simple-hero-api.md\n        - tutorial/fastapi/response-model.md\n        - tutorial/fastapi/multiple-models.md\n        - tutorial/fastapi/read-one.md\n        - tutorial/fastapi/limit-and-offset.md\n        - tutorial/fastapi/update.md\n        - tutorial/fastapi/update-extra-data.md\n        - tutorial/fastapi/delete.md\n        - tutorial/fastapi/session-with-dependency.md\n        - tutorial/fastapi/teams.md\n        - tutorial/fastapi/relationships.md\n        - tutorial/fastapi/tests.md\n    - Advanced User Guide:\n      - advanced/index.md\n      - advanced/decimal.md\n      - advanced/uuid.md\n  - Resources:\n    - resources/index.md\n    - help.md\n    - contributing.md\n    - management-tasks.md\n  - About:\n    - about/index.md\n    - alternatives.md\n    - management.md\n  - release-notes.md\n\nmarkdown_extensions:\n  # Material for MkDocs\n  material.extensions.preview:\n    targets:\n      include:\n        - \"*\"\n  # Python Markdown\n  abbr:\n  attr_list:\n  footnotes:\n  md_in_html:\n  tables:\n  toc:\n    permalink: true\n\n  # Python Markdown Extensions\n  pymdownx.betterem:\n    smart_enable: all\n  pymdownx.caret:\n  pymdownx.highlight:\n    line_spans: __span\n  pymdownx.inlinehilite:\n  pymdownx.keys:\n  pymdownx.mark:\n  pymdownx.superfences:\n    custom_fences:\n    - name: mermaid\n      class: mermaid\n      format: !!python/name:pymdownx.superfences.fence_code_format\n  pymdownx.tilde:\n\n  # pymdownx blocks\n  pymdownx.blocks.admonition:\n    types:\n    - note\n    - attention\n    - caution\n    - danger\n    - error\n    - tip\n    - hint\n    - warning\n    # Custom types\n    - info\n  pymdownx.blocks.details:\n  pymdownx.blocks.tab:\n    alternate_style: True\n\n  # Other extensions\n  mdx_include:\n  markdown_include_variants:\n\nextra:\n  social:\n  - icon: fontawesome/brands/github-alt\n    link: https://github.com/fastapi/sqlmodel\n  - icon: fontawesome/brands/twitter\n    link: https://twitter.com/tiangolo\n  - icon: fontawesome/brands/linkedin\n    link: https://www.linkedin.com/in/tiangolo\n  - icon: fontawesome/brands/dev\n    link: https://dev.to/tiangolo\n  - icon: fontawesome/brands/medium\n    link: https://medium.com/@tiangolo\n  - icon: fontawesome/solid/globe\n    link: https://tiangolo.com\n\nextra_css:\n  - css/termynal.css\n  - css/custom.css\n\nextra_javascript:\n  - js/termynal.js\n  - js/custom.js\n\nhooks:\n  - scripts/mkdocs_hooks.py\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"pdm-backend\"]\nbuild-backend = \"pdm.backend\"\n\n[project]\nname = \"sqlmodel\"\ndynamic = [\"version\"]\ndescription = \"SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\nauthors = [\n    { name = \"Sebastián Ramírez\", email = \"tiangolo@gmail.com\" },\n]\nlicense = \"MIT\"\nlicense-files = [\"LICENSE\"]\n\nclassifiers = [\n    \"Development Status :: 4 - Beta\",\n    \"Framework :: AsyncIO\",\n    \"Intended Audience :: Developers\",\n    \"Intended Audience :: Science/Research\",\n    \"Intended Audience :: System Administrators\",\n    \"Programming Language :: Python :: 3 :: Only\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Topic :: Database\",\n    \"Topic :: Database :: Database Engines/Servers\",\n    \"Topic :: Internet\",\n    \"Topic :: Internet :: WWW/HTTP :: HTTP Servers\",\n    \"Topic :: Internet :: WWW/HTTP\",\n    \"Typing :: Typed\",\n]\n\ndependencies = [\n    \"SQLAlchemy >=2.0.14,<2.1.0\",\n    \"pydantic>=2.11.0\",\n]\n\n[project.urls]\nHomepage = \"https://github.com/fastapi/sqlmodel\"\nDocumentation = \"https://sqlmodel.tiangolo.com\"\nRepository = \"https://github.com/fastapi/sqlmodel\"\nIssues = \"https://github.com/fastapi/sqlmodel/issues\"\nChangelog = \"https://sqlmodel.tiangolo.com/release-notes/\"\n\n[dependency-groups]\ndev = [\n    { include-group = \"docs\" },\n    { include-group = \"tests\" },\n    \"prek>=0.2.24,<1.0.0\",\n]\ndocs = [\n    \"black >=24.1.0\",\n    \"cairosvg >=2.9.0\",\n    \"griffe-typingdoc >=0.3.0\",\n    \"griffe-warnings-deprecated >=1.1.0\",\n    \"markdown-include-variants >=0.0.8\",\n    \"mdx-include >=1.4.1\",\n    \"mkdocs-macros-plugin >=1.5.0\",\n    \"mkdocs-material >=9.7.5\",\n    \"mkdocs-redirects >=1.2.1\",\n    \"mkdocstrings[python] >=1.0.3\",\n    \"pillow >=12.1.1\",\n    \"pyyaml >=5.3.1\",\n    \"typer >=0.24.1\",\n]\ngithub-actions = [\n    \"httpx >=0.28.1\",\n    \"pydantic >=2.5.3\",\n    \"pydantic-settings >=2.1.0\",\n    \"pygithub >=2.3.0\",\n    \"smokeshow >=0.5.0\",\n]\ntests = [\n    \"black >=24.1.0\",\n    \"coverage[toml] >=6.2\",\n    \"dirty-equals >=0.11\",\n    \"fastapi >=0.128.0\",\n    \"httpx >=0.28.1\",\n    \"jinja2 >=3.1.6\",\n    \"mypy >=1.19.1\",\n    \"pytest >=7.0.1\",\n    \"ruff >=0.15.6\",\n    \"typing-extensions >=4.15.0\",\n]\n\n[tool.pdm]\nversion = { source = \"file\", path = \"sqlmodel/__init__.py\" }\ndistribution = true\n\n[tool.pdm.build]\nsource-includes = [\n    \"tests/\",\n    \"docs_src/\",\n    \"scripts/\",\n    \"sqlmodel/sql/expression.py.jinja2\",\n]\n\n[tool.coverage.run]\nparallel = true\ndata_file = \"coverage/.coverage\"\nsource = [\n    \"docs_src\",\n    \"tests\",\n    \"sqlmodel\"\n]\ncontext = '${CONTEXT}'\ndynamic_context = \"test_function\"\nrelative_files = true\n\n[tool.coverage.report]\nshow_missing = true\nsort = \"-Cover\"\nexclude_lines = [\n    \"pragma: no cover\",\n    \"@overload\",\n    'if __name__ == \"__main__\":',\n    \"if TYPE_CHECKING:\",\n]\n\n[tool.coverage.html]\nshow_contexts = true\n\n[tool.mypy]\nstrict = true\nexclude = \"sqlmodel.sql._expression_select_gen\"\n\n[[tool.mypy.overrides]]\nmodule = \"docs_src.*\"\ndisallow_incomplete_defs = false\ndisallow_untyped_defs = false\ndisallow_untyped_calls = false\n\n[tool.ruff.lint]\nselect = [\n    \"E\",  # pycodestyle errors\n    \"W\",  # pycodestyle warnings\n    \"F\",  # pyflakes\n    \"I\",  # isort\n    \"B\",  # flake8-bugbear\n    \"C4\",  # flake8-comprehensions\n    \"UP\", # pyupgrade\n]\nignore = [\n    \"E501\",  # line too long, handled by black\n    \"B008\",  # do not perform function calls in argument defaults\n    \"C901\",  # too complex\n    \"W191\", # indentation contains tabs\n]\n\n[tool.ruff.lint.per-file-ignores]\n# \"__init__.py\" = [\"F401\"]\n\n[tool.ruff.lint.isort]\nknown-third-party = [\"sqlmodel\", \"sqlalchemy\", \"pydantic\", \"fastapi\"]\n\n[tool.ruff.lint.pyupgrade]\n# Preserve types, even if a file imports `from __future__ import annotations`.\nkeep-runtime-typing = true\n"
  },
  {
    "path": "scripts/deploy_docs_status.py",
    "content": "import logging\nimport re\nfrom typing import Literal\n\nfrom github import Auth, Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\nsite_domain = \"sqlmodel.tiangolo.com\"\n\n\nclass Settings(BaseSettings):\n    github_repository: str\n    github_token: SecretStr\n    deploy_url: str | None = None\n    commit_sha: str\n    run_id: int\n    state: Literal[\"pending\", \"success\", \"error\"] = \"pending\"\n\n\nclass LinkData(BaseModel):\n    previous_link: str\n    preview_link: str\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(auth=Auth.Token(settings.github_token.get_secret_value()))\n    repo = g.get_repo(settings.github_repository)\n    use_pr = next(\n        (pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None\n    )\n    if not use_pr:\n        logging.error(f\"No PR found for hash: {settings.commit_sha}\")\n        return\n    commits = list(use_pr.get_commits())\n    current_commit = [c for c in commits if c.sha == settings.commit_sha][0]\n    run_url = f\"https://github.com/{settings.github_repository}/actions/runs/{settings.run_id}\"\n    if settings.state == \"pending\":\n        current_commit.create_status(\n            state=\"pending\",\n            description=\"Deploying Docs\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"No deploy URL available yet\")\n        return\n    if settings.state == \"error\":\n        current_commit.create_status(\n            state=\"error\",\n            description=\"Error Deploying Docs\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"Error deploying docs\")\n        return\n    assert settings.state == \"success\"\n    if not settings.deploy_url:\n        current_commit.create_status(\n            state=\"success\",\n            description=\"No Docs Changes\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"No docs changes found\")\n        return\n    assert settings.deploy_url\n    current_commit.create_status(\n        state=\"success\",\n        description=\"Docs Deployed\",\n        context=\"deploy-docs\",\n        target_url=run_url,\n    )\n\n    files = list(use_pr.get_files())\n    docs_files = [f for f in files if f.filename.startswith(\"docs/\")]\n\n    deploy_url = settings.deploy_url.rstrip(\"/\")\n    links: list[LinkData] = []\n    for f in docs_files:\n        match = re.match(r\"docs/(.*)\", f.filename)\n        if not match:\n            continue\n        path = match.group(1)\n        if path.endswith(\"index.md\"):\n            use_path = path.replace(\"index.md\", \"\")\n        else:\n            use_path = path.replace(\".md\", \"/\")\n        link = LinkData(\n            previous_link=f\"https://{site_domain}/{use_path}\",\n            preview_link=f\"{deploy_url}/{use_path}\",\n        )\n        links.append(link)\n        links.sort(key=lambda x: x.preview_link)\n\n    header = \"## 📝 Docs preview\"\n    message = header\n    message += f\"\\n\\nLast commit {settings.commit_sha} at: {deploy_url}\"\n\n    if links:\n        message += \"\\n\\n### Modified Pages\\n\\n\"\n        for link in links:\n            message += f\"* {link.preview_link}\"\n            message += f\" - ([before]({link.previous_link}))\"\n            message += \"\\n\"\n\n    print(message)\n    issue = use_pr.as_issue()\n    comments = list(issue.get_comments())\n    for comment in comments:\n        if (\n            comment.body.startswith(header)\n            and comment.user.login == \"github-actions[bot]\"\n        ):\n            comment.edit(message)\n            break\n    else:\n        issue.create_comment(message)\n\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/docs.py",
    "content": "import logging\nimport os\nimport re\nimport shutil\nimport subprocess\nfrom http.server import HTTPServer, SimpleHTTPRequestHandler\nfrom pathlib import Path\n\nimport mkdocs.utils\nimport typer\nfrom jinja2 import Template\nfrom ruff.__main__ import find_ruff_bin\n\nlogging.basicConfig(level=logging.INFO)\n\nmkdocs_name = \"mkdocs.yml\"\ndocs_path = Path(\"docs\")\nen_docs_path = Path(\"\")\n\napp = typer.Typer()\n\n\n@app.callback()\ndef callback() -> None:\n    # For MacOS with Cairo\n    os.environ[\"DYLD_FALLBACK_LIBRARY_PATH\"] = \"/opt/homebrew/lib\"\n\n\nindex_sponsors_template = \"\"\"\n{% if sponsors %}\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\"></a>\n{% endfor %}\n{% endif %}\n\"\"\"\n\n\ndef generate_readme_content() -> str:\n    en_index = en_docs_path / \"docs\" / \"index.md\"\n    content = en_index.read_text(\"utf-8\")\n    match_pre = re.search(r\"</style>\\n\\n\", content)\n    match_start = re.search(r\"<!-- sponsors -->\", content)\n    match_end = re.search(r\"<!-- /sponsors -->\", content)\n    sponsors_data_path = en_docs_path / \"data\" / \"sponsors.yml\"\n    sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding=\"utf-8\"))\n    if not (match_start and match_end):\n        raise RuntimeError(\"Couldn't auto-generate sponsors section\")\n    if not match_pre:\n        raise RuntimeError(\"Couldn't find pre section (<style>) in index.md\")\n    frontmatter_end = match_pre.end()\n    pre_end = match_start.end()\n    post_start = match_end.start()\n    template = Template(index_sponsors_template)\n    message = template.render(sponsors=sponsors)\n    pre_content = content[frontmatter_end:pre_end]\n    post_content = content[post_start:]\n    new_content = pre_content + message + post_content\n    # Remove content between <!-- only-mkdocs --> and <!-- /only-mkdocs -->\n    new_content = re.sub(\n        r\"<!-- only-mkdocs -->.*?<!-- /only-mkdocs -->\",\n        \"\",\n        new_content,\n        flags=re.DOTALL,\n    )\n    return new_content\n\n\n@app.command()\ndef generate_readme() -> None:\n    \"\"\"\n    Generate README.md content from main index.md\n    \"\"\"\n    typer.echo(\"Generating README\")\n    readme_path = Path(\"README.md\")\n    new_content = generate_readme_content()\n    readme_path.write_text(new_content, encoding=\"utf-8\")\n\n\n@app.command()\ndef verify_readme() -> None:\n    \"\"\"\n    Verify README.md content from main index.md\n    \"\"\"\n    typer.echo(\"Verifying README\")\n    readme_path = Path(\"README.md\")\n    generated_content = generate_readme_content()\n    readme_content = readme_path.read_text(\"utf-8\")\n    if generated_content != readme_content:\n        typer.secho(\n            \"README.md outdated from the latest index.md\", color=typer.colors.RED\n        )\n        raise typer.Abort()\n    typer.echo(\"Valid README ✅\")\n\n\n@app.command()\ndef live(dirty: bool = False) -> None:\n    \"\"\"\n    Serve with livereload a docs site for a specific language.\n\n    This only shows the actual translated files, not the placeholders created with\n    build-all.\n\n    Takes an optional LANG argument with the name of the language to serve, by default\n    en.\n    \"\"\"\n    # Enable line numbers during local development to make it easier to highlight\n    args = [\"mkdocs\", \"serve\", \"--dev-addr\", \"127.0.0.1:8008\"]\n    if dirty:\n        args.append(\"--dirty\")\n    subprocess.run(args, env={**os.environ, \"LINENUMS\": \"true\"}, check=True)\n\n\n@app.command()\ndef build() -> None:\n    \"\"\"\n    Build the docs.\n    \"\"\"\n    print(\"Building docs\")\n    subprocess.run([\"mkdocs\", \"build\"], check=True)\n    typer.secho(\"Successfully built docs\", color=typer.colors.GREEN)\n\n\n@app.command()\ndef serve() -> None:\n    \"\"\"\n    A quick server to preview a built site.\n\n    For development, prefer the command live (or just mkdocs serve).\n\n    This is here only to preview the documentation site.\n\n    Make sure you run the build command first.\n    \"\"\"\n    typer.echo(\"Warning: this is a very simple server.\")\n    typer.echo(\"For development, use the command live instead.\")\n    typer.echo(\"This is here only to preview the documentation site.\")\n    typer.echo(\"Make sure you run the build command first.\")\n    os.chdir(\"site\")\n    server_address = (\"\", 8008)\n    server = HTTPServer(server_address, SimpleHTTPRequestHandler)\n    typer.echo(\"Serving at: http://127.0.0.1:8008\")\n    server.serve_forever()\n\n\n@app.command()\ndef generate_docs_src_versions_for_file(file_path: Path) -> None:\n    target_versions = [\"py39\", \"py310\"]\n    full_path_str = str(file_path)\n    for target_version in target_versions:\n        if f\"_{target_version}\" in full_path_str:\n            logging.info(\n                f\"Skipping {file_path}, already a version file for {target_version}\"\n            )\n            return\n    base_content = file_path.read_text(encoding=\"utf-8\")\n    previous_content = {base_content}\n    for target_version in target_versions:\n        version_result = subprocess.run(\n            [\n                find_ruff_bin(),\n                \"check\",\n                \"--target-version\",\n                target_version,\n                \"--fix\",\n                \"--unsafe-fixes\",\n                \"-\",\n            ],\n            input=base_content.encode(\"utf-8\"),\n            capture_output=True,\n        )\n        content_target = version_result.stdout.decode(\"utf-8\")\n        format_result = subprocess.run(\n            [find_ruff_bin(), \"format\", \"-\"],\n            input=content_target.encode(\"utf-8\"),\n            capture_output=True,\n        )\n        content_format = format_result.stdout.decode(\"utf-8\")\n        if content_format in previous_content:\n            continue\n        previous_content.add(content_format)\n        # Determine where the version label should go: in the parent directory\n        # name or in the file name, matching the source structure.\n        label_in_parent = False\n        for v in target_versions:\n            if f\"_{v}\" in file_path.parent.name:\n                label_in_parent = True\n                break\n        if label_in_parent:\n            parent_name = file_path.parent.name\n            for v in target_versions:\n                parent_name = parent_name.replace(f\"_{v}\", \"\")\n            new_parent = file_path.parent.parent / f\"{parent_name}_{target_version}\"\n            new_parent.mkdir(parents=True, exist_ok=True)\n            version_file = new_parent / file_path.name\n        else:\n            base_name = file_path.stem\n            for v in target_versions:\n                if base_name.endswith(f\"_{v}\"):\n                    base_name = base_name[: -len(f\"_{v}\")]\n                    break\n            version_file = file_path.with_name(f\"{base_name}_{target_version}.py\")\n        logging.info(f\"Writing to {version_file}\")\n        version_file.write_text(content_format, encoding=\"utf-8\")\n\n\n@app.command()\ndef generate_docs_src_versions() -> None:\n    \"\"\"\n    Generate Python version-specific files for all .py files in docs_src.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    for py_file in sorted(docs_src_path.rglob(\"*.py\")):\n        generate_docs_src_versions_for_file(py_file)\n\n\n@app.command()\ndef copy_py39_to_py310() -> None:\n    \"\"\"\n    For each docs_src file/directory with a _py39 label that has no _py310\n    counterpart, copy it with the _py310 label.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    # Handle directory-level labels (e.g. app_b_an_py39/)\n    for dir_path in sorted(docs_src_path.rglob(\"*_py39\")):\n        if not dir_path.is_dir():\n            continue\n        py310_dir = dir_path.parent / dir_path.name.replace(\"_py39\", \"_py310\")\n        if py310_dir.exists():\n            continue\n        logging.info(f\"Copying directory {dir_path} -> {py310_dir}\")\n        shutil.copytree(dir_path, py310_dir)\n    # Handle file-level labels (e.g. tutorial001_py39.py)\n    for file_path in sorted(docs_src_path.rglob(\"*_py39.py\")):\n        if not file_path.is_file():\n            continue\n        # Skip files inside _py39 directories (already handled above)\n        if \"_py39\" in file_path.parent.name:\n            continue\n        py310_file = file_path.with_name(\n            file_path.name.replace(\"_py39.py\", \"_py310.py\")\n        )\n        if py310_file.exists():\n            continue\n        logging.info(f\"Copying file {file_path} -> {py310_file}\")\n        shutil.copy2(file_path, py310_file)\n\n\n@app.command()\ndef update_docs_includes_py39_to_py310() -> None:\n    \"\"\"\n    Update .md files in docs/en/ to replace _py39 includes with _py310 versions.\n\n    For each include line referencing a _py39 file or directory in docs_src, replace\n    the _py39 label with _py310.\n    \"\"\"\n    include_pattern = re.compile(r\"\\{[^}]*docs_src/[^}]*_py39[^}]*\\.py[^}]*\\}\")\n    count = 0\n    for md_file in sorted(en_docs_path.rglob(\"*.md\")):\n        content = md_file.read_text(encoding=\"utf-8\")\n        if \"_py39\" not in content:\n            continue\n        new_content = include_pattern.sub(\n            lambda m: m.group(0).replace(\"_py39\", \"_py310\"), content\n        )\n        if new_content != content:\n            md_file.write_text(new_content, encoding=\"utf-8\")\n            count += 1\n            logging.info(f\"Updated includes in {md_file}\")\n    print(f\"Updated {count} file(s) ✅\")\n\n\n@app.command()\ndef remove_unused_docs_src() -> None:\n    \"\"\"\n    Delete .py files in docs_src that are not included in any .md file under docs/.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    # Collect all docs .md content referencing docs_src\n    all_docs_content = \"\"\n    for md_file in docs_path.rglob(\"*.md\"):\n        all_docs_content += md_file.read_text(encoding=\"utf-8\")\n    # Build a set of directory-based package roots (e.g. docs_src/bigger_applications/app_py39)\n    # where at least one file is referenced in docs. All files in these directories\n    # should be kept since they may be internally imported by the referenced files.\n    used_package_dirs: set[Path] = set()\n    for py_file in docs_src_path.rglob(\"*.py\"):\n        if py_file.name == \"__init__.py\":\n            continue\n        rel_path = str(py_file)\n        if rel_path in all_docs_content:\n            parts = py_file.relative_to(docs_src_path).parts\n            if len(parts) > 2 and not py_file.name.startswith(\"tutorial\"):\n                # File is inside a package directory (e.g.\n                # docs_src/tutorial/fastapi/app_testing/tutorial001_py310/).\n                # Mark the immediate parent as a used package so sibling\n                # files (likely imported by the referenced file) are kept.\n                used_package_dirs.add(py_file.parent)\n    removed = 0\n    for py_file in sorted(docs_src_path.rglob(\"*.py\")):\n        if py_file.name == \"__init__.py\":\n            continue\n        # Build the relative path as it appears in includes (e.g. docs_src/first_steps/tutorial001.py)\n        rel_path = str(py_file)\n        if rel_path in all_docs_content:\n            continue\n        # If this file is inside a directory-based package where any sibling is\n        # referenced, keep it (it's likely imported internally).\n        if py_file.parent in used_package_dirs:\n            continue\n        # Check if the _an counterpart (or non-_an counterpart) is referenced.\n        # If either variant is included, keep both.\n        # Handle both file-level _an (tutorial001_an.py) and directory-level _an\n        # (app_an/main.py)\n        counterpart_found = False\n        full_path_str = str(py_file)\n        if \"_an\" in py_file.stem:\n            # This is an _an file, check if the non-_an version is referenced\n            counterpart = full_path_str.replace(\n                f\"/{py_file.stem}\", f\"/{py_file.stem.replace('_an', '', 1)}\"\n            )\n            if counterpart in all_docs_content:\n                counterpart_found = True\n        else:\n            # This is a non-_an file, check if there's an _an version referenced\n            # Insert _an before any version suffix or at the end of the stem\n            stem = py_file.stem\n            for suffix in (\"_py39\", \"_py310\"):\n                if suffix in stem:\n                    an_stem = stem.replace(suffix, f\"_an{suffix}\", 1)\n                    break\n            else:\n                an_stem = f\"{stem}_an\"\n            counterpart = full_path_str.replace(f\"/{stem}.\", f\"/{an_stem}.\")\n            if counterpart in all_docs_content:\n                counterpart_found = True\n        # Also check directory-level _an counterparts\n        if not counterpart_found:\n            parent_name = py_file.parent.name\n            if \"_an\" in parent_name:\n                counterpart_parent = parent_name.replace(\"_an\", \"\", 1)\n                counterpart_dir = str(py_file).replace(\n                    f\"/{parent_name}/\", f\"/{counterpart_parent}/\"\n                )\n                if counterpart_dir in all_docs_content:\n                    counterpart_found = True\n            else:\n                # Try inserting _an into parent directory name\n                for suffix in (\"_py39\", \"_py310\"):\n                    if suffix in parent_name:\n                        an_parent = parent_name.replace(suffix, f\"_an{suffix}\", 1)\n                        break\n                else:\n                    an_parent = f\"{parent_name}_an\"\n                counterpart_dir = str(py_file).replace(\n                    f\"/{parent_name}/\", f\"/{an_parent}/\"\n                )\n                if counterpart_dir in all_docs_content:\n                    counterpart_found = True\n        if counterpart_found:\n            continue\n        logging.info(f\"Removing unused file: {py_file}\")\n        py_file.unlink()\n        removed += 1\n    # Clean up directories that are empty or only contain __init__.py / __pycache__\n    for dir_path in sorted(docs_src_path.rglob(\"*\"), reverse=True):\n        if not dir_path.is_dir():\n            continue\n        remaining = [\n            f\n            for f in dir_path.iterdir()\n            if f.name != \"__pycache__\" and f.name != \"__init__.py\"\n        ]\n        if not remaining:\n            logging.info(f\"Removing empty/init-only directory: {dir_path}\")\n            shutil.rmtree(dir_path)\n    print(f\"Removed {removed} unused file(s) ✅\")\n\n\nif __name__ == \"__main__\":\n    app()\n"
  },
  {
    "path": "scripts/format.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nruff check sqlmodel tests docs_src scripts --fix\nruff format sqlmodel tests docs_src scripts\n"
  },
  {
    "path": "scripts/generate_select.py",
    "content": "import os\nfrom itertools import product\nfrom pathlib import Path\n\nimport black\nfrom jinja2 import Template\nfrom pydantic import BaseModel\n\ntemplate_path = (\n    Path(__file__).parent.parent / \"sqlmodel/sql/_expression_select_gen.py.jinja2\"\n)\ndestiny_path = Path(__file__).parent.parent / \"sqlmodel/sql/_expression_select_gen.py\"\n\n\nnumber_of_types = 4\n\n\nclass Arg(BaseModel):\n    name: str\n    annotation: str\n\n\narg_groups: list[Arg] = []\n\nsignatures: list[tuple[list[Arg], list[str]]] = []\n\nfor total_args in range(2, number_of_types + 1):\n    arg_types_tuples = product([\"model\", \"scalar\"], repeat=total_args)\n    for arg_type_tuple in arg_types_tuples:\n        args: list[Arg] = []\n        return_types: list[str] = []\n        for i, arg_type in enumerate(arg_type_tuple):\n            if arg_type == \"scalar\":\n                t_var = f\"_TScalar_{i}\"\n                arg = Arg(name=f\"entity_{i}\", annotation=t_var)\n                ret_type = t_var\n            else:\n                t_type = f\"_T{i}\"\n                t_var = f\"_TCCA[{t_type}]\"\n                arg = Arg(name=f\"__ent{i}\", annotation=t_var)\n                ret_type = t_type\n            args.append(arg)\n            return_types.append(ret_type)\n        signatures.append((args, return_types))\n\ntemplate: Template = Template(template_path.read_text())\n\nresult = template.render(number_of_types=number_of_types, signatures=signatures)\n\nresult = (\n    \"# WARNING: do not modify this code, it is generated by \"\n    \"_expression_select_gen.py.jinja2\\n\\n\" + result\n)\n\nresult = black.format_str(result, mode=black.Mode())\n\ncurrent_content = destiny_path.read_text()\n\nif current_content != result and os.getenv(\"CHECK_JINJA\"):\n    raise RuntimeError(\n        \"sqlmodel/sql/expression.py content not update with Jinja2 template\"\n    )\n\ndestiny_path.write_text(result)\n"
  },
  {
    "path": "scripts/lint.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nmypy sqlmodel\nmypy tests/test_select_typing.py\nruff check sqlmodel tests docs_src scripts\nruff format sqlmodel tests docs_src scripts --check\n"
  },
  {
    "path": "scripts/mkdocs_hooks.py",
    "content": "from typing import Any\n\nfrom mkdocs.config.defaults import MkDocsConfig\nfrom mkdocs.structure.files import Files\nfrom mkdocs.structure.nav import Link, Navigation, Section\nfrom mkdocs.structure.pages import Page\n\n\ndef generate_renamed_section_items(\n    items: list[Page | Section | Link], *, config: MkDocsConfig\n) -> list[Page | Section | Link]:\n    new_items: list[Page | Section | Link] = []\n    for item in items:\n        if isinstance(item, Section):\n            new_title = item.title\n            new_children = generate_renamed_section_items(item.children, config=config)\n            first_child = new_children[0]\n            if isinstance(first_child, Page):\n                if first_child.file.src_path.endswith(\"index.md\"):\n                    # Read the source so that the title is parsed and available\n                    first_child.read_source(config=config)\n                    new_title = first_child.title or new_title\n            # Creating a new section makes it render it collapsed by default\n            # no idea why, so, let's just modify the existing one\n            # new_section = Section(title=new_title, children=new_children)\n            item.title = new_title\n            item.children = new_children\n            new_items.append(item)\n        else:\n            new_items.append(item)\n    return new_items\n\n\ndef on_nav(\n    nav: Navigation, *, config: MkDocsConfig, files: Files, **kwargs: Any\n) -> Navigation:\n    new_items = generate_renamed_section_items(nav.items, config=config)\n    return Navigation(items=new_items, pages=nav.pages)\n"
  },
  {
    "path": "scripts/test.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\ncoverage run -m pytest tests\ncoverage combine\ncoverage report\ncoverage html\n"
  },
  {
    "path": "sqlmodel/__init__.py",
    "content": "__version__ = \"0.0.37\"\n\n# Re-export from SQLAlchemy\nfrom sqlalchemy.engine import create_engine as create_engine\nfrom sqlalchemy.engine import create_mock_engine as create_mock_engine\nfrom sqlalchemy.engine import engine_from_config as engine_from_config\nfrom sqlalchemy.inspection import inspect as inspect\nfrom sqlalchemy.pool import QueuePool as QueuePool\nfrom sqlalchemy.pool import StaticPool as StaticPool\nfrom sqlalchemy.schema import BLANK_SCHEMA as BLANK_SCHEMA\nfrom sqlalchemy.schema import DDL as DDL\nfrom sqlalchemy.schema import CheckConstraint as CheckConstraint\nfrom sqlalchemy.schema import Column as Column\nfrom sqlalchemy.schema import ColumnDefault as ColumnDefault\nfrom sqlalchemy.schema import Computed as Computed\nfrom sqlalchemy.schema import Constraint as Constraint\nfrom sqlalchemy.schema import DefaultClause as DefaultClause\nfrom sqlalchemy.schema import FetchedValue as FetchedValue\nfrom sqlalchemy.schema import ForeignKey as ForeignKey\nfrom sqlalchemy.schema import ForeignKeyConstraint as ForeignKeyConstraint\nfrom sqlalchemy.schema import Identity as Identity\nfrom sqlalchemy.schema import Index as Index\nfrom sqlalchemy.schema import MetaData as MetaData\nfrom sqlalchemy.schema import PrimaryKeyConstraint as PrimaryKeyConstraint\nfrom sqlalchemy.schema import Sequence as Sequence\nfrom sqlalchemy.schema import Table as Table\nfrom sqlalchemy.schema import UniqueConstraint as UniqueConstraint\nfrom sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT\nfrom sqlalchemy.sql import (\n    LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,\n)\nfrom sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE\nfrom sqlalchemy.sql import (\n    LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,\n)\nfrom sqlalchemy.sql import alias as alias\nfrom sqlalchemy.sql import bindparam as bindparam\nfrom sqlalchemy.sql import column as column\nfrom sqlalchemy.sql import delete as delete\nfrom sqlalchemy.sql import except_ as except_\nfrom sqlalchemy.sql import except_all as except_all\nfrom sqlalchemy.sql import exists as exists\nfrom sqlalchemy.sql import false as false\nfrom sqlalchemy.sql import func as func\nfrom sqlalchemy.sql import insert as insert\nfrom sqlalchemy.sql import intersect as intersect\nfrom sqlalchemy.sql import intersect_all as intersect_all\nfrom sqlalchemy.sql import join as join\nfrom sqlalchemy.sql import lambda_stmt as lambda_stmt\nfrom sqlalchemy.sql import lateral as lateral\nfrom sqlalchemy.sql import literal as literal\nfrom sqlalchemy.sql import literal_column as literal_column\nfrom sqlalchemy.sql import modifier as modifier\nfrom sqlalchemy.sql import null as null\nfrom sqlalchemy.sql import nullsfirst as nullsfirst\nfrom sqlalchemy.sql import nullslast as nullslast\nfrom sqlalchemy.sql import outerjoin as outerjoin\nfrom sqlalchemy.sql import outparam as outparam\nfrom sqlalchemy.sql import table as table\nfrom sqlalchemy.sql import tablesample as tablesample\nfrom sqlalchemy.sql import text as text\nfrom sqlalchemy.sql import true as true\nfrom sqlalchemy.sql import union as union\nfrom sqlalchemy.sql import union_all as union_all\nfrom sqlalchemy.sql import update as update\nfrom sqlalchemy.sql import values as values\nfrom sqlalchemy.types import ARRAY as ARRAY\nfrom sqlalchemy.types import BIGINT as BIGINT\nfrom sqlalchemy.types import BINARY as BINARY\nfrom sqlalchemy.types import BLOB as BLOB\nfrom sqlalchemy.types import BOOLEAN as BOOLEAN\nfrom sqlalchemy.types import CHAR as CHAR\nfrom sqlalchemy.types import CLOB as CLOB\nfrom sqlalchemy.types import DATE as DATE\nfrom sqlalchemy.types import DATETIME as DATETIME\nfrom sqlalchemy.types import DECIMAL as DECIMAL\nfrom sqlalchemy.types import DOUBLE as DOUBLE\nfrom sqlalchemy.types import DOUBLE_PRECISION as DOUBLE_PRECISION\nfrom sqlalchemy.types import FLOAT as FLOAT\nfrom sqlalchemy.types import INT as INT\nfrom sqlalchemy.types import INTEGER as INTEGER\nfrom sqlalchemy.types import JSON as JSON\nfrom sqlalchemy.types import NCHAR as NCHAR\nfrom sqlalchemy.types import NUMERIC as NUMERIC\nfrom sqlalchemy.types import NVARCHAR as NVARCHAR\nfrom sqlalchemy.types import REAL as REAL\nfrom sqlalchemy.types import SMALLINT as SMALLINT\nfrom sqlalchemy.types import TEXT as TEXT\nfrom sqlalchemy.types import TIME as TIME\nfrom sqlalchemy.types import TIMESTAMP as TIMESTAMP\nfrom sqlalchemy.types import UUID as UUID\nfrom sqlalchemy.types import VARBINARY as VARBINARY\nfrom sqlalchemy.types import VARCHAR as VARCHAR\nfrom sqlalchemy.types import BigInteger as BigInteger\nfrom sqlalchemy.types import Boolean as Boolean\nfrom sqlalchemy.types import Date as Date\nfrom sqlalchemy.types import DateTime as DateTime\nfrom sqlalchemy.types import Double as Double\nfrom sqlalchemy.types import Enum as Enum\nfrom sqlalchemy.types import Float as Float\nfrom sqlalchemy.types import Integer as Integer\nfrom sqlalchemy.types import Interval as Interval\nfrom sqlalchemy.types import LargeBinary as LargeBinary\nfrom sqlalchemy.types import Numeric as Numeric\nfrom sqlalchemy.types import PickleType as PickleType\nfrom sqlalchemy.types import SmallInteger as SmallInteger\nfrom sqlalchemy.types import String as String\nfrom sqlalchemy.types import Text as Text\nfrom sqlalchemy.types import Time as Time\nfrom sqlalchemy.types import TupleType as TupleType\nfrom sqlalchemy.types import TypeDecorator as TypeDecorator\nfrom sqlalchemy.types import Unicode as Unicode\nfrom sqlalchemy.types import UnicodeText as UnicodeText\nfrom sqlalchemy.types import Uuid as Uuid\n\n# From SQLModel, modifications of SQLAlchemy or equivalents of Pydantic\nfrom .main import Field as Field\nfrom .main import Relationship as Relationship\nfrom .main import SQLModel as SQLModel\nfrom .orm.session import Session as Session\nfrom .sql.expression import all_ as all_\nfrom .sql.expression import and_ as and_\nfrom .sql.expression import any_ as any_\nfrom .sql.expression import asc as asc\nfrom .sql.expression import between as between\nfrom .sql.expression import case as case\nfrom .sql.expression import cast as cast\nfrom .sql.expression import col as col\nfrom .sql.expression import collate as collate\nfrom .sql.expression import desc as desc\nfrom .sql.expression import distinct as distinct\nfrom .sql.expression import extract as extract\nfrom .sql.expression import funcfilter as funcfilter\nfrom .sql.expression import not_ as not_\nfrom .sql.expression import nulls_first as nulls_first\nfrom .sql.expression import nulls_last as nulls_last\nfrom .sql.expression import or_ as or_\nfrom .sql.expression import over as over\nfrom .sql.expression import select as select\nfrom .sql.expression import tuple_ as tuple_\nfrom .sql.expression import type_coerce as type_coerce\nfrom .sql.expression import within_group as within_group\nfrom .sql.sqltypes import AutoString as AutoString\n"
  },
  {
    "path": "sqlmodel/_compat.py",
    "content": "import sys\nimport types\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\nfrom contextvars import ContextVar\nfrom dataclasses import dataclass\nfrom typing import (\n    TYPE_CHECKING,\n    Annotated,\n    Any,\n    ForwardRef,\n    TypeAlias,\n    TypeVar,\n    Union,\n    get_args,\n    get_origin,\n)\n\nfrom annotated_types import MaxLen\nfrom pydantic import VERSION as P_VERSION\nfrom pydantic import BaseModel\nfrom pydantic import ConfigDict as ConfigDict\nfrom pydantic._internal._fields import PydanticMetadata\nfrom pydantic._internal._model_construction import ModelMetaclass as ModelMetaclass\nfrom pydantic._internal._repr import Representation as Representation\nfrom pydantic.fields import FieldInfo\nfrom pydantic_core import PydanticUndefined as Undefined\nfrom pydantic_core import PydanticUndefinedType as PydanticUndefinedType\n\nBaseConfig = ConfigDict\nUndefinedType = PydanticUndefinedType\nPYDANTIC_MINOR_VERSION = tuple(int(i) for i in P_VERSION.split(\".\")[:2])\n\n\nif TYPE_CHECKING:\n    from .main import RelationshipInfo, SQLModel\n\nUnionType = getattr(types, \"UnionType\", Union)\nNoneType = type(None)\nT = TypeVar(\"T\")\nInstanceOrType: TypeAlias = T | type[T]\n_TSQLModel = TypeVar(\"_TSQLModel\", bound=\"SQLModel\")\n\n\nclass FakeMetadata:\n    max_length: int | None = None\n    max_digits: int | None = None\n    decimal_places: int | None = None\n\n\n@dataclass\nclass ObjectWithUpdateWrapper:\n    obj: Any\n    update: dict[str, Any]\n\n    def __getattribute__(self, __name: str) -> Any:\n        update = super().__getattribute__(\"update\")\n        obj = super().__getattribute__(\"obj\")\n        if __name in update:\n            return update[__name]\n        return getattr(obj, __name)\n\n\ndef _is_union_type(t: Any) -> bool:\n    return t is UnionType or t is Union\n\n\nfinish_init: ContextVar[bool] = ContextVar(\"finish_init\", default=True)\n\n\n@contextmanager\ndef partial_init() -> Generator[None, None, None]:\n    token = finish_init.set(False)\n    yield\n    finish_init.reset(token)\n\n\nclass SQLModelConfig(BaseConfig, total=False):\n    table: bool | None\n    registry: Any | None\n\n\ndef get_model_fields(model: InstanceOrType[BaseModel]) -> dict[str, \"FieldInfo\"]:\n    # TODO: refactor the usage of this function to always pass the class\n    # not the instance, and then remove this extra check\n    # this is for compatibility with Pydantic v3\n    if isinstance(model, type):\n        use_model = model\n    else:\n        use_model = model.__class__\n    return use_model.model_fields\n\n\ndef init_pydantic_private_attrs(new_object: InstanceOrType[\"SQLModel\"]) -> None:\n    object.__setattr__(new_object, \"__pydantic_fields_set__\", set())\n    object.__setattr__(new_object, \"__pydantic_extra__\", None)\n    object.__setattr__(new_object, \"__pydantic_private__\", None)\n\n\ndef get_annotations(class_dict: dict[str, Any]) -> dict[str, Any]:\n    raw_annotations: dict[str, Any] = class_dict.get(\"__annotations__\", {})\n    if sys.version_info >= (3, 14) and \"__annotations__\" not in class_dict:\n        # See https://github.com/pydantic/pydantic/pull/11991\n        from annotationlib import (\n            Format,\n            call_annotate_function,\n            get_annotate_from_class_namespace,\n        )\n\n        if annotate := get_annotate_from_class_namespace(class_dict):\n            raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF)\n    return raw_annotations\n\n\ndef is_table_model_class(cls: type[Any]) -> bool:\n    config = getattr(cls, \"model_config\", {})\n    if config:\n        return config.get(\"table\", False) or False\n    return False\n\n\ndef get_relationship_to(\n    name: str,\n    rel_info: \"RelationshipInfo\",\n    annotation: Any,\n) -> Any:\n    origin = get_origin(annotation)\n    use_annotation = annotation\n    # Direct relationships (e.g. 'Team' or Team) have None as an origin\n    if origin is None:\n        if isinstance(use_annotation, ForwardRef):\n            use_annotation = use_annotation.__forward_arg__\n        else:\n            return use_annotation\n    # If Union (e.g. Optional), get the real field\n    elif _is_union_type(origin):\n        use_annotation = get_args(annotation)\n        if len(use_annotation) > 2:\n            raise ValueError(\"Cannot have a (non-optional) union as a SQLAlchemy field\")\n        arg1, arg2 = use_annotation\n        if arg1 is NoneType and arg2 is not NoneType:\n            use_annotation = arg2\n        elif arg2 is NoneType and arg1 is not NoneType:\n            use_annotation = arg1\n        else:\n            raise ValueError(\n                \"Cannot have a Union of None and None as a SQLAlchemy field\"\n            )\n\n    # If a list, then also get the real field\n    elif origin is list:\n        use_annotation = get_args(annotation)[0]\n\n    return get_relationship_to(name=name, rel_info=rel_info, annotation=use_annotation)\n\n\ndef is_field_noneable(field: \"FieldInfo\") -> bool:\n    if getattr(field, \"nullable\", Undefined) is not Undefined:\n        return field.nullable  # type: ignore\n    origin = get_origin(field.annotation)\n    if origin is not None and _is_union_type(origin):\n        args = get_args(field.annotation)\n        if any(arg is NoneType for arg in args):\n            return True\n    if not field.is_required():\n        if field.default is Undefined:\n            return False\n        if field.annotation is None or field.annotation is NoneType:\n            return True\n        return False\n    return False\n\n\ndef get_sa_type_from_type_annotation(annotation: Any) -> Any:\n    # Resolve Optional fields\n    if annotation is None:\n        raise ValueError(\"Missing field type\")\n    origin = get_origin(annotation)\n    if origin is None:\n        return annotation\n    elif origin is Annotated:\n        return get_sa_type_from_type_annotation(get_args(annotation)[0])\n    if _is_union_type(origin):\n        bases = get_args(annotation)\n        if len(bases) > 2:\n            raise ValueError(\"Cannot have a (non-optional) union as a SQLAlchemy field\")\n        # Non optional unions are not allowed\n        if bases[0] is not NoneType and bases[1] is not NoneType:\n            raise ValueError(\"Cannot have a (non-optional) union as a SQLAlchemy field\")\n        # Optional unions are allowed\n        use_type = bases[0] if bases[0] is not NoneType else bases[1]\n        return get_sa_type_from_type_annotation(use_type)\n    return origin\n\n\ndef get_sa_type_from_field(field: Any) -> Any:\n    type_: Any = field.annotation\n    return get_sa_type_from_type_annotation(type_)\n\n\ndef get_field_metadata(field: Any) -> Any:\n    for meta in field.metadata:\n        if isinstance(meta, (PydanticMetadata, MaxLen)):\n            return meta\n    return FakeMetadata()\n\n\ndef sqlmodel_table_construct(\n    *,\n    self_instance: _TSQLModel,\n    values: dict[str, Any],\n    _fields_set: set[str] | None = None,\n) -> _TSQLModel:\n    # Copy from Pydantic's BaseModel.construct()\n    # Ref: https://github.com/pydantic/pydantic/blob/v2.5.2/pydantic/main.py#L198\n    # Modified to not include everything, only the model fields, and to\n    # set relationships\n    # SQLModel override to get class SQLAlchemy __dict__ attributes and\n    # set them back in after creating the object\n    # new_obj = cls.__new__(cls)\n    cls = type(self_instance)\n    old_dict = self_instance.__dict__.copy()\n    # End SQLModel override\n\n    fields_values: dict[str, Any] = {}\n    defaults: dict[\n        str, Any\n    ] = {}  # keeping this separate from `fields_values` helps us compute `_fields_set`\n    for name, field in cls.model_fields.items():\n        if field.alias and field.alias in values:\n            fields_values[name] = values.pop(field.alias)\n        elif name in values:\n            fields_values[name] = values.pop(name)\n        elif not field.is_required():\n            defaults[name] = field.get_default(call_default_factory=True)\n    if _fields_set is None:\n        _fields_set = set(fields_values.keys())\n    fields_values.update(defaults)\n\n    _extra: dict[str, Any] | None = None\n    if cls.model_config.get(\"extra\") == \"allow\":\n        _extra = {}\n        for k, v in values.items():\n            _extra[k] = v\n    # SQLModel override, do not include everything, only the model fields\n    # else:\n    #     fields_values.update(values)\n    # End SQLModel override\n    # SQLModel override\n    # Do not set __dict__, instead use setattr to trigger SQLAlchemy\n    # object.__setattr__(new_obj, \"__dict__\", fields_values)\n    # instrumentation\n    for key, value in {**old_dict, **fields_values}.items():\n        setattr(self_instance, key, value)\n    # End SQLModel override\n    object.__setattr__(self_instance, \"__pydantic_fields_set__\", _fields_set)\n    if not cls.__pydantic_root_model__:\n        object.__setattr__(self_instance, \"__pydantic_extra__\", _extra)\n\n    if cls.__pydantic_post_init__:\n        self_instance.model_post_init(None)\n    elif not cls.__pydantic_root_model__:\n        # Note: if there are any private attributes, cls.__pydantic_post_init__ would exist\n        # Since it doesn't, that means that `__pydantic_private__` should be set to None\n        object.__setattr__(self_instance, \"__pydantic_private__\", None)\n    # SQLModel override, set relationships\n    # Get and set any relationship objects\n    for key in self_instance.__sqlmodel_relationships__:\n        value = values.get(key, Undefined)\n        if value is not Undefined:\n            setattr(self_instance, key, value)\n    # End SQLModel override\n    return self_instance\n\n\ndef sqlmodel_validate(\n    cls: type[_TSQLModel],\n    obj: Any,\n    *,\n    strict: bool | None = None,\n    from_attributes: bool | None = None,\n    context: dict[str, Any] | None = None,\n    update: dict[str, Any] | None = None,\n) -> _TSQLModel:\n    if not is_table_model_class(cls):\n        new_obj: _TSQLModel = cls.__new__(cls)\n    else:\n        # If table, create the new instance normally to make SQLAlchemy create\n        # the _sa_instance_state attribute\n        # The wrapper of this function should use with _partial_init()\n        with partial_init():\n            new_obj = cls()\n    # SQLModel Override to get class SQLAlchemy __dict__ attributes and\n    # set them back in after creating the object\n    old_dict = new_obj.__dict__.copy()\n    use_obj = obj\n    if isinstance(obj, dict) and update:\n        use_obj = {**obj, **update}\n    elif update:\n        use_obj = ObjectWithUpdateWrapper(obj=obj, update=update)\n    cls.__pydantic_validator__.validate_python(\n        use_obj,\n        strict=strict,\n        from_attributes=from_attributes,\n        context=context,\n        self_instance=new_obj,\n    )\n    # Capture fields set to restore it later\n    fields_set = new_obj.__pydantic_fields_set__.copy()\n    if not is_table_model_class(cls):\n        # If not table, normal Pydantic code, set __dict__\n        new_obj.__dict__ = {**old_dict, **new_obj.__dict__}\n    else:\n        # Do not set __dict__, instead use setattr to trigger SQLAlchemy\n        # instrumentation\n        for key, value in {**old_dict, **new_obj.__dict__}.items():\n            setattr(new_obj, key, value)\n    # Restore fields set\n    object.__setattr__(new_obj, \"__pydantic_fields_set__\", fields_set)\n    # Get and set any relationship objects\n    if is_table_model_class(cls):\n        for key in new_obj.__sqlmodel_relationships__:\n            value = getattr(use_obj, key, Undefined)\n            if value is not Undefined:\n                setattr(new_obj, key, value)\n    return new_obj\n\n\ndef sqlmodel_init(*, self: \"SQLModel\", data: dict[str, Any]) -> None:\n    old_dict = self.__dict__.copy()\n    if not is_table_model_class(self.__class__):\n        self.__pydantic_validator__.validate_python(\n            data,\n            self_instance=self,\n        )\n    else:\n        sqlmodel_table_construct(\n            self_instance=self,\n            values=data,\n        )\n    object.__setattr__(\n        self,\n        \"__dict__\",\n        {**old_dict, **self.__dict__},\n    )\n"
  },
  {
    "path": "sqlmodel/default.py",
    "content": "from typing import Any, TypeVar\n\n\nclass _DefaultPlaceholder:\n    \"\"\"\n    You shouldn't use this class directly.\n\n    It's used internally to recognize when a default value has been overwritten, even\n    if the overridden default value was truthy.\n    \"\"\"\n\n    def __init__(self, value: Any):\n        self.value = value\n\n    def __bool__(self) -> bool:\n        return bool(self.value)\n\n    def __eq__(self, o: object) -> bool:\n        return isinstance(o, _DefaultPlaceholder) and o.value == self.value\n\n\n_TDefaultType = TypeVar(\"_TDefaultType\")\n\n\ndef Default(value: _TDefaultType) -> _TDefaultType:\n    \"\"\"\n    You shouldn't use this function directly.\n\n    It's used internally to recognize when a default value has been overwritten, even\n    if the overridden default value was truthy.\n    \"\"\"\n    return _DefaultPlaceholder(value)  # type: ignore\n"
  },
  {
    "path": "sqlmodel/ext/__init__.py",
    "content": ""
  },
  {
    "path": "sqlmodel/ext/asyncio/__init__.py",
    "content": ""
  },
  {
    "path": "sqlmodel/ext/asyncio/session.py",
    "content": "from collections.abc import Mapping, Sequence\nfrom typing import (\n    Any,\n    TypeVar,\n    cast,\n    overload,\n)\n\nfrom sqlalchemy import util\nfrom sqlalchemy.engine.cursor import CursorResult\nfrom sqlalchemy.engine.interfaces import _CoreAnyExecuteParams\nfrom sqlalchemy.engine.result import Result, ScalarResult, TupleResult\nfrom sqlalchemy.ext.asyncio import AsyncSession as _AsyncSession\nfrom sqlalchemy.ext.asyncio.result import _ensure_sync_result\nfrom sqlalchemy.ext.asyncio.session import _EXECUTE_OPTIONS\nfrom sqlalchemy.orm._typing import OrmExecuteOptionsParameter\nfrom sqlalchemy.sql.base import Executable as _Executable\nfrom sqlalchemy.sql.dml import UpdateBase\nfrom sqlalchemy.util.concurrency import greenlet_spawn\nfrom typing_extensions import deprecated\n\nfrom ...orm.session import Session\nfrom ...sql.base import Executable\nfrom ...sql.expression import Select, SelectOfScalar\n\n_TSelectParam = TypeVar(\"_TSelectParam\", bound=Any)\n\n\nclass AsyncSession(_AsyncSession):\n    sync_session_class: type[Session] = Session\n    sync_session: Session\n\n    @overload\n    async def exec(\n        self,\n        statement: Select[_TSelectParam],\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> TupleResult[_TSelectParam]: ...\n\n    @overload\n    async def exec(\n        self,\n        statement: SelectOfScalar[_TSelectParam],\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> ScalarResult[_TSelectParam]: ...\n\n    @overload\n    async def exec(\n        self,\n        statement: UpdateBase,\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> CursorResult[Any]: ...\n\n    async def exec(\n        self,\n        statement: Select[_TSelectParam]\n        | SelectOfScalar[_TSelectParam]\n        | Executable[_TSelectParam]\n        | UpdateBase,\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> TupleResult[_TSelectParam] | ScalarResult[_TSelectParam] | CursorResult[Any]:\n        if execution_options:\n            execution_options = util.immutabledict(execution_options).union(\n                _EXECUTE_OPTIONS\n            )\n        else:\n            execution_options = _EXECUTE_OPTIONS\n\n        result = await greenlet_spawn(\n            self.sync_session.exec,\n            statement,\n            params=params,\n            execution_options=execution_options,\n            bind_arguments=bind_arguments,\n            _parent_execute_state=_parent_execute_state,\n            _add_event=_add_event,\n        )\n        result_value = await _ensure_sync_result(\n            cast(Result[_TSelectParam], result), self.exec\n        )\n        return result_value  # type: ignore\n\n    @deprecated(\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.execute()`.\n\n        This is the original SQLAlchemy `session.execute()` method that returns objects\n        of type `Row`, and that you have to call `scalars()` to get the model objects.\n\n        For example:\n\n        ```Python\n        result = await session.execute(select(Hero))\n        heroes = result.scalars().all()\n        ```\n\n        instead you could use `exec()`:\n\n        ```Python\n        result = await session.exec(select(Hero))\n        heroes = result.all()\n        ```\n        \"\"\"\n    )\n    async def execute(\n        self,\n        statement: _Executable,\n        params: _CoreAnyExecuteParams | None = None,\n        *,\n        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> Result[Any]:\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.execute()`.\n\n        This is the original SQLAlchemy `session.execute()` method that returns objects\n        of type `Row`, and that you have to call `scalars()` to get the model objects.\n\n        For example:\n\n        ```Python\n        result = await session.execute(select(Hero))\n        heroes = result.scalars().all()\n        ```\n\n        instead you could use `exec()`:\n\n        ```Python\n        result = await session.exec(select(Hero))\n        heroes = result.all()\n        ```\n        \"\"\"\n        return await super().execute(\n            statement,\n            params=params,\n            execution_options=execution_options,\n            bind_arguments=bind_arguments,\n            _parent_execute_state=_parent_execute_state,\n            _add_event=_add_event,\n        )\n"
  },
  {
    "path": "sqlmodel/main.py",
    "content": "from __future__ import annotations\n\nimport builtins\nimport ipaddress\nimport uuid\nimport weakref\nfrom collections.abc import Callable, Mapping, Sequence, Set\nfrom dataclasses import dataclass\nfrom datetime import date, datetime, time, timedelta\nfrom decimal import Decimal\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Literal,\n    TypeAlias,\n    TypeVar,\n    Union,\n    cast,\n    get_origin,\n    overload,\n)\n\nfrom pydantic import BaseModel, EmailStr\nfrom pydantic.fields import FieldInfo as PydanticFieldInfo\nfrom sqlalchemy import (\n    Boolean,\n    Column,\n    Date,\n    DateTime,\n    Float,\n    ForeignKey,\n    Integer,\n    Interval,\n    Numeric,\n    inspect,\n)\nfrom sqlalchemy import Enum as sa_Enum\nfrom sqlalchemy.orm import (\n    Mapped,\n    RelationshipProperty,\n    declared_attr,\n    registry,\n    relationship,\n)\nfrom sqlalchemy.orm.attributes import set_attribute\nfrom sqlalchemy.orm.decl_api import DeclarativeMeta\nfrom sqlalchemy.orm.instrumentation import is_instrumented\nfrom sqlalchemy.sql.schema import MetaData\nfrom sqlalchemy.sql.sqltypes import LargeBinary, Time, Uuid\nfrom typing_extensions import deprecated\n\nfrom ._compat import (  # type: ignore[attr-defined]\n    PYDANTIC_MINOR_VERSION,\n    BaseConfig,\n    ModelMetaclass,\n    Representation,\n    SQLModelConfig,\n    Undefined,\n    UndefinedType,\n    finish_init,\n    get_annotations,\n    get_field_metadata,\n    get_model_fields,\n    get_relationship_to,\n    get_sa_type_from_field,\n    init_pydantic_private_attrs,\n    is_field_noneable,\n    is_table_model_class,\n    sqlmodel_init,\n    sqlmodel_validate,\n)\nfrom .sql.sqltypes import AutoString\n\nif TYPE_CHECKING:\n    from pydantic._internal._model_construction import ModelMetaclass as ModelMetaclass\n    from pydantic._internal._repr import Representation as Representation\n    from pydantic_core import PydanticUndefined as Undefined\n    from pydantic_core import PydanticUndefinedType as UndefinedType\n\n_T = TypeVar(\"_T\")\nNoArgAnyCallable = Callable[[], Any]\nIncEx: TypeAlias = (\n    set[int]\n    | set[str]\n    | Mapping[int, Union[\"IncEx\", bool]]\n    | Mapping[str, Union[\"IncEx\", bool]]\n)\nOnDeleteType = Literal[\"CASCADE\", \"SET NULL\", \"RESTRICT\"]\n\n\ndef __dataclass_transform__(\n    *,\n    eq_default: bool = True,\n    order_default: bool = False,\n    kw_only_default: bool = False,\n    field_descriptors: tuple[type | Callable[..., Any], ...] = (()),\n) -> Callable[[_T], _T]:\n    return lambda a: a\n\n\nclass FieldInfo(PydanticFieldInfo):  # type: ignore[misc]\n    # mypy - ignore that PydanticFieldInfo is @final\n    def __init__(self, default: Any = Undefined, **kwargs: Any) -> None:\n        primary_key = kwargs.pop(\"primary_key\", False)\n        nullable = kwargs.pop(\"nullable\", Undefined)\n        foreign_key = kwargs.pop(\"foreign_key\", Undefined)\n        ondelete = kwargs.pop(\"ondelete\", Undefined)\n        unique = kwargs.pop(\"unique\", False)\n        index = kwargs.pop(\"index\", Undefined)\n        sa_type = kwargs.pop(\"sa_type\", Undefined)\n        sa_column = kwargs.pop(\"sa_column\", Undefined)\n        sa_column_args = kwargs.pop(\"sa_column_args\", Undefined)\n        sa_column_kwargs = kwargs.pop(\"sa_column_kwargs\", Undefined)\n        if sa_column is not Undefined:\n            if sa_column_args is not Undefined:\n                raise RuntimeError(\n                    \"Passing sa_column_args is not supported when \"\n                    \"also passing a sa_column\"\n                )\n            if sa_column_kwargs is not Undefined:\n                raise RuntimeError(\n                    \"Passing sa_column_kwargs is not supported when \"\n                    \"also passing a sa_column\"\n                )\n            if primary_key is not Undefined:\n                raise RuntimeError(\n                    \"Passing primary_key is not supported when also passing a sa_column\"\n                )\n            if nullable is not Undefined:\n                raise RuntimeError(\n                    \"Passing nullable is not supported when also passing a sa_column\"\n                )\n            if foreign_key is not Undefined:\n                raise RuntimeError(\n                    \"Passing foreign_key is not supported when also passing a sa_column\"\n                )\n            if ondelete is not Undefined:\n                raise RuntimeError(\n                    \"Passing ondelete is not supported when also passing a sa_column\"\n                )\n            if unique is not Undefined:\n                raise RuntimeError(\n                    \"Passing unique is not supported when also passing a sa_column\"\n                )\n            if index is not Undefined:\n                raise RuntimeError(\n                    \"Passing index is not supported when also passing a sa_column\"\n                )\n            if sa_type is not Undefined:\n                raise RuntimeError(\n                    \"Passing sa_type is not supported when also passing a sa_column\"\n                )\n        if ondelete is not Undefined:\n            if foreign_key is Undefined:\n                raise RuntimeError(\"ondelete can only be used with foreign_key\")\n        super().__init__(default=default, **kwargs)\n        self.primary_key = primary_key\n        self.nullable = nullable\n        self.foreign_key = foreign_key\n        self.ondelete = ondelete\n        self.unique = unique\n        self.index = index\n        self.sa_type = sa_type\n        self.sa_column = sa_column\n        self.sa_column_args = sa_column_args\n        self.sa_column_kwargs = sa_column_kwargs\n\n\nclass RelationshipInfo(Representation):\n    def __init__(\n        self,\n        *,\n        back_populates: str | None = None,\n        cascade_delete: bool | None = False,\n        passive_deletes: bool | Literal[\"all\"] | None = False,\n        link_model: Any | None = None,\n        sa_relationship: RelationshipProperty | None = None,  # type: ignore\n        sa_relationship_args: Sequence[Any] | None = None,\n        sa_relationship_kwargs: Mapping[str, Any] | None = None,\n    ) -> None:\n        if sa_relationship is not None:\n            if sa_relationship_args is not None:\n                raise RuntimeError(\n                    \"Passing sa_relationship_args is not supported when \"\n                    \"also passing a sa_relationship\"\n                )\n            if sa_relationship_kwargs is not None:\n                raise RuntimeError(\n                    \"Passing sa_relationship_kwargs is not supported when \"\n                    \"also passing a sa_relationship\"\n                )\n        self.back_populates = back_populates\n        self.cascade_delete = cascade_delete\n        self.passive_deletes = passive_deletes\n        self.link_model = link_model\n        self.sa_relationship = sa_relationship\n        self.sa_relationship_args = sa_relationship_args\n        self.sa_relationship_kwargs = sa_relationship_kwargs\n\n\n@dataclass\nclass FieldInfoMetadata:\n    primary_key: bool | UndefinedType = Undefined\n    nullable: bool | UndefinedType = Undefined\n    foreign_key: Any = Undefined\n    ondelete: OnDeleteType | UndefinedType = Undefined\n    unique: bool | UndefinedType = Undefined\n    index: bool | UndefinedType = Undefined\n    sa_type: type[Any] | UndefinedType = Undefined\n    sa_column: Column[Any] | UndefinedType = Undefined\n    sa_column_args: Sequence[Any] | UndefinedType = Undefined\n    sa_column_kwargs: Mapping[str, Any] | UndefinedType = Undefined\n\n\ndef _get_sqlmodel_field_metadata(field_info: Any) -> FieldInfoMetadata | None:\n    metadata_items = getattr(field_info, \"metadata\", None)\n    if metadata_items:\n        for meta in metadata_items:\n            if isinstance(meta, FieldInfoMetadata):\n                return meta\n    return None\n\n\ndef _get_sqlmodel_field_value(\n    field_info: Any, attribute: str, default: Any = Undefined\n) -> Any:\n    metadata = _get_sqlmodel_field_metadata(field_info)\n    if metadata is not None and hasattr(metadata, attribute):\n        return getattr(metadata, attribute)\n    return getattr(field_info, attribute, default)\n\n\n# include sa_type, sa_column_args, sa_column_kwargs\n@overload\ndef Field(\n    default: Any = Undefined,\n    *,\n    default_factory: NoArgAnyCallable | None = None,\n    alias: str | None = None,\n    validation_alias: str | None = None,\n    serialization_alias: str | None = None,\n    title: str | None = None,\n    description: str | None = None,\n    exclude: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    include: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    const: bool | None = None,\n    gt: float | None = None,\n    ge: float | None = None,\n    lt: float | None = None,\n    le: float | None = None,\n    multiple_of: float | None = None,\n    max_digits: int | None = None,\n    decimal_places: int | None = None,\n    min_items: int | None = None,\n    max_items: int | None = None,\n    unique_items: bool | None = None,\n    min_length: int | None = None,\n    max_length: int | None = None,\n    allow_mutation: bool = True,\n    regex: str | None = None,\n    discriminator: str | None = None,\n    repr: bool = True,\n    primary_key: bool | UndefinedType = Undefined,\n    foreign_key: Any = Undefined,\n    unique: bool | UndefinedType = Undefined,\n    nullable: bool | UndefinedType = Undefined,\n    index: bool | UndefinedType = Undefined,\n    sa_type: type[Any] | UndefinedType = Undefined,\n    sa_column_args: Sequence[Any] | UndefinedType = Undefined,\n    sa_column_kwargs: Mapping[str, Any] | UndefinedType = Undefined,\n    schema_extra: dict[str, Any] | None = None,\n) -> Any: ...\n\n\n# When foreign_key is str, include ondelete\n# include sa_type, sa_column_args, sa_column_kwargs\n@overload\ndef Field(\n    default: Any = Undefined,\n    *,\n    default_factory: NoArgAnyCallable | None = None,\n    alias: str | None = None,\n    validation_alias: str | None = None,\n    serialization_alias: str | None = None,\n    title: str | None = None,\n    description: str | None = None,\n    exclude: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    include: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    const: bool | None = None,\n    gt: float | None = None,\n    ge: float | None = None,\n    lt: float | None = None,\n    le: float | None = None,\n    multiple_of: float | None = None,\n    max_digits: int | None = None,\n    decimal_places: int | None = None,\n    min_items: int | None = None,\n    max_items: int | None = None,\n    unique_items: bool | None = None,\n    min_length: int | None = None,\n    max_length: int | None = None,\n    allow_mutation: bool = True,\n    regex: str | None = None,\n    discriminator: str | None = None,\n    repr: bool = True,\n    primary_key: bool | UndefinedType = Undefined,\n    foreign_key: str,\n    ondelete: OnDeleteType | UndefinedType = Undefined,\n    unique: bool | UndefinedType = Undefined,\n    nullable: bool | UndefinedType = Undefined,\n    index: bool | UndefinedType = Undefined,\n    sa_type: type[Any] | UndefinedType = Undefined,\n    sa_column_args: Sequence[Any] | UndefinedType = Undefined,\n    sa_column_kwargs: Mapping[str, Any] | UndefinedType = Undefined,\n    schema_extra: dict[str, Any] | None = None,\n) -> Any: ...\n\n\n# Include sa_column, don't include\n# primary_key\n# foreign_key\n# ondelete\n# unique\n# nullable\n# index\n# sa_type\n# sa_column_args\n# sa_column_kwargs\n@overload\ndef Field(\n    default: Any = Undefined,\n    *,\n    default_factory: NoArgAnyCallable | None = None,\n    alias: str | None = None,\n    validation_alias: str | None = None,\n    serialization_alias: str | None = None,\n    title: str | None = None,\n    description: str | None = None,\n    exclude: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    include: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    const: bool | None = None,\n    gt: float | None = None,\n    ge: float | None = None,\n    lt: float | None = None,\n    le: float | None = None,\n    multiple_of: float | None = None,\n    max_digits: int | None = None,\n    decimal_places: int | None = None,\n    min_items: int | None = None,\n    max_items: int | None = None,\n    unique_items: bool | None = None,\n    min_length: int | None = None,\n    max_length: int | None = None,\n    allow_mutation: bool = True,\n    regex: str | None = None,\n    discriminator: str | None = None,\n    repr: bool = True,\n    sa_column: Column[Any] | UndefinedType = Undefined,\n    schema_extra: dict[str, Any] | None = None,\n) -> Any: ...\n\n\ndef Field(\n    default: Any = Undefined,\n    *,\n    default_factory: NoArgAnyCallable | None = None,\n    alias: str | None = None,\n    validation_alias: str | None = None,\n    serialization_alias: str | None = None,\n    title: str | None = None,\n    description: str | None = None,\n    exclude: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    include: Set[int | str] | Mapping[int | str, Any] | Any = None,\n    const: bool | None = None,\n    gt: float | None = None,\n    ge: float | None = None,\n    lt: float | None = None,\n    le: float | None = None,\n    multiple_of: float | None = None,\n    max_digits: int | None = None,\n    decimal_places: int | None = None,\n    min_items: int | None = None,\n    max_items: int | None = None,\n    unique_items: bool | None = None,\n    min_length: int | None = None,\n    max_length: int | None = None,\n    allow_mutation: bool = True,\n    regex: str | None = None,\n    discriminator: str | None = None,\n    repr: bool = True,\n    primary_key: bool | UndefinedType = Undefined,\n    foreign_key: Any = Undefined,\n    ondelete: OnDeleteType | UndefinedType = Undefined,\n    unique: bool | UndefinedType = Undefined,\n    nullable: bool | UndefinedType = Undefined,\n    index: bool | UndefinedType = Undefined,\n    sa_type: type[Any] | UndefinedType = Undefined,\n    sa_column: Column | UndefinedType = Undefined,  # type: ignore\n    sa_column_args: Sequence[Any] | UndefinedType = Undefined,\n    sa_column_kwargs: Mapping[str, Any] | UndefinedType = Undefined,\n    schema_extra: dict[str, Any] | None = None,\n) -> Any:\n    current_schema_extra = schema_extra or {}\n    # Extract possible alias settings from schema_extra so we can control precedence\n    schema_validation_alias = current_schema_extra.pop(\"validation_alias\", None)\n    schema_serialization_alias = current_schema_extra.pop(\"serialization_alias\", None)\n    field_info_kwargs = {\n        \"alias\": alias,\n        \"title\": title,\n        \"description\": description,\n        \"exclude\": exclude,\n        \"include\": include,\n        \"const\": const,\n        \"gt\": gt,\n        \"ge\": ge,\n        \"lt\": lt,\n        \"le\": le,\n        \"multiple_of\": multiple_of,\n        \"max_digits\": max_digits,\n        \"decimal_places\": decimal_places,\n        \"min_items\": min_items,\n        \"max_items\": max_items,\n        \"unique_items\": unique_items,\n        \"min_length\": min_length,\n        \"max_length\": max_length,\n        \"allow_mutation\": allow_mutation,\n        \"regex\": regex,\n        \"discriminator\": discriminator,\n        \"repr\": repr,\n        \"primary_key\": primary_key,\n        \"foreign_key\": foreign_key,\n        \"ondelete\": ondelete,\n        \"unique\": unique,\n        \"nullable\": nullable,\n        \"index\": index,\n        \"sa_type\": sa_type,\n        \"sa_column\": sa_column,\n        \"sa_column_args\": sa_column_args,\n        \"sa_column_kwargs\": sa_column_kwargs,\n        **current_schema_extra,\n    }\n\n    # explicit params > schema_extra > alias propagation\n    field_info_kwargs[\"validation_alias\"] = (\n        validation_alias or schema_validation_alias or alias\n    )\n    field_info_kwargs[\"serialization_alias\"] = (\n        serialization_alias or schema_serialization_alias or alias\n    )\n\n    field_info = FieldInfo(\n        default,\n        default_factory=default_factory,\n        **field_info_kwargs,\n    )\n    field_metadata = FieldInfoMetadata(\n        primary_key=primary_key,\n        nullable=nullable,\n        foreign_key=foreign_key,\n        ondelete=ondelete,\n        unique=unique,\n        index=index,\n        sa_type=sa_type,\n        sa_column=sa_column,\n        sa_column_args=sa_column_args,\n        sa_column_kwargs=sa_column_kwargs,\n    )\n    if hasattr(field_info, \"metadata\"):\n        field_info.metadata.append(field_metadata)\n    return field_info\n\n\n@overload\ndef Relationship(\n    *,\n    back_populates: str | None = None,\n    cascade_delete: bool | None = False,\n    passive_deletes: bool | Literal[\"all\"] | None = False,\n    link_model: Any | None = None,\n    sa_relationship_args: Sequence[Any] | None = None,\n    sa_relationship_kwargs: Mapping[str, Any] | None = None,\n) -> Any: ...\n\n\n@overload\ndef Relationship(\n    *,\n    back_populates: str | None = None,\n    cascade_delete: bool | None = False,\n    passive_deletes: bool | Literal[\"all\"] | None = False,\n    link_model: Any | None = None,\n    sa_relationship: RelationshipProperty[Any] | None = None,\n) -> Any: ...\n\n\ndef Relationship(\n    *,\n    back_populates: str | None = None,\n    cascade_delete: bool | None = False,\n    passive_deletes: bool | Literal[\"all\"] | None = False,\n    link_model: Any | None = None,\n    sa_relationship: RelationshipProperty[Any] | None = None,\n    sa_relationship_args: Sequence[Any] | None = None,\n    sa_relationship_kwargs: Mapping[str, Any] | None = None,\n) -> Any:\n    relationship_info = RelationshipInfo(\n        back_populates=back_populates,\n        cascade_delete=cascade_delete,\n        passive_deletes=passive_deletes,\n        link_model=link_model,\n        sa_relationship=sa_relationship,\n        sa_relationship_args=sa_relationship_args,\n        sa_relationship_kwargs=sa_relationship_kwargs,\n    )\n    return relationship_info\n\n\n@__dataclass_transform__(kw_only_default=True, field_descriptors=(Field, FieldInfo))\nclass SQLModelMetaclass(ModelMetaclass, DeclarativeMeta):\n    __sqlmodel_relationships__: dict[str, RelationshipInfo]\n    model_config: SQLModelConfig\n    model_fields: ClassVar[dict[str, FieldInfo]]\n\n    # Replicate SQLAlchemy\n    def __setattr__(cls, name: str, value: Any) -> None:\n        if is_table_model_class(cls):\n            DeclarativeMeta.__setattr__(cls, name, value)\n        else:\n            super().__setattr__(name, value)\n\n    def __delattr__(cls, name: str) -> None:\n        if is_table_model_class(cls):\n            DeclarativeMeta.__delattr__(cls, name)\n        else:\n            super().__delattr__(name)\n\n    # From Pydantic\n    def __new__(\n        cls,\n        name: str,\n        bases: tuple[type[Any], ...],\n        class_dict: dict[str, Any],\n        **kwargs: Any,\n    ) -> Any:\n        relationships: dict[str, RelationshipInfo] = {}\n        dict_for_pydantic = {}\n        original_annotations = get_annotations(class_dict)\n        pydantic_annotations = {}\n        relationship_annotations = {}\n        for k, v in class_dict.items():\n            if isinstance(v, RelationshipInfo):\n                relationships[k] = v\n            else:\n                dict_for_pydantic[k] = v\n        for k, v in original_annotations.items():\n            if k in relationships:\n                relationship_annotations[k] = v\n            else:\n                pydantic_annotations[k] = v\n        dict_used = {\n            **dict_for_pydantic,\n            \"__weakref__\": None,\n            \"__sqlmodel_relationships__\": relationships,\n            \"__annotations__\": pydantic_annotations,\n        }\n        # Duplicate logic from Pydantic to filter config kwargs because if they are\n        # passed directly including the registry Pydantic will pass them over to the\n        # superclass causing an error\n        allowed_config_kwargs: set[str] = {\n            key\n            for key in dir(BaseConfig)\n            if not (\n                key.startswith(\"__\") and key.endswith(\"__\")\n            )  # skip dunder methods and attributes\n        }\n        config_kwargs = {\n            key: kwargs[key] for key in kwargs.keys() & allowed_config_kwargs\n        }\n        new_cls = cast(\n            \"SQLModel\", super().__new__(cls, name, bases, dict_used, **config_kwargs)\n        )\n        new_cls.__annotations__ = {\n            **relationship_annotations,\n            **pydantic_annotations,\n            **new_cls.__annotations__,\n        }\n\n        def get_config(name: str) -> Any:\n            config_class_value = new_cls.model_config.get(name, Undefined)\n            if config_class_value is not Undefined:\n                return config_class_value\n            kwarg_value = kwargs.get(name, Undefined)\n            if kwarg_value is not Undefined:\n                return kwarg_value\n            return Undefined\n\n        config_table = get_config(\"table\")\n        if config_table is True:\n            # If it was passed by kwargs, ensure it's also set in config\n            new_cls.model_config[\"table\"] = config_table\n            for k, v in get_model_fields(new_cls).items():\n                col = get_column_from_field(v)\n                setattr(new_cls, k, col)\n            # Set a config flag to tell FastAPI that this should be read with a field\n            # in orm_mode instead of preemptively converting it to a dict.\n            # This could be done by reading new_cls.model_config['table'] in FastAPI, but\n            # that's very specific about SQLModel, so let's have another config that\n            # other future tools based on Pydantic can use.\n            new_cls.model_config[\"read_from_attributes\"] = True  # type: ignore[typeddict-unknown-key]\n            # For compatibility with older versions\n            # TODO: remove this in the future\n            new_cls.model_config[\"read_with_orm_mode\"] = True  # type: ignore[typeddict-unknown-key]\n\n        config_registry = get_config(\"registry\")\n        if config_registry is not Undefined:\n            config_registry = cast(registry, config_registry)\n            # If it was passed by kwargs, ensure it's also set in config\n            new_cls.model_config[\"registry\"] = config_table\n            setattr(new_cls, \"_sa_registry\", config_registry)  # noqa: B010\n            setattr(new_cls, \"metadata\", config_registry.metadata)  # noqa: B010\n            setattr(new_cls, \"__abstract__\", True)  # noqa: B010\n        return new_cls\n\n    # Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models\n    def __init__(\n        cls, classname: str, bases: tuple[type, ...], dict_: dict[str, Any], **kw: Any\n    ) -> None:\n        # Only one of the base classes (or the current one) should be a table model\n        # this allows FastAPI cloning a SQLModel for the response_model without\n        # trying to create a new SQLAlchemy, for a new table, with the same name, that\n        # triggers an error\n        base_is_table = any(is_table_model_class(base) for base in bases)\n        if is_table_model_class(cls) and not base_is_table:\n            for rel_name, rel_info in cls.__sqlmodel_relationships__.items():\n                if rel_info.sa_relationship:\n                    # There's a SQLAlchemy relationship declared, that takes precedence\n                    # over anything else, use that and continue with the next attribute\n                    setattr(cls, rel_name, rel_info.sa_relationship)  # Fix #315\n                    continue\n                raw_ann = cls.__annotations__[rel_name]\n                origin: Any = get_origin(raw_ann)\n                if origin is Mapped:\n                    ann = raw_ann.__args__[0]\n                else:\n                    ann = raw_ann\n                    # Plain forward references, for models not yet defined, are not\n                    # handled well by SQLAlchemy without Mapped, so, wrap the\n                    # annotations in Mapped here\n                    cls.__annotations__[rel_name] = Mapped[ann]  # type: ignore[valid-type]\n                relationship_to = get_relationship_to(\n                    name=rel_name, rel_info=rel_info, annotation=ann\n                )\n                rel_kwargs: dict[str, Any] = {}\n                if rel_info.back_populates:\n                    rel_kwargs[\"back_populates\"] = rel_info.back_populates\n                if rel_info.cascade_delete:\n                    rel_kwargs[\"cascade\"] = \"all, delete-orphan\"\n                if rel_info.passive_deletes:\n                    rel_kwargs[\"passive_deletes\"] = rel_info.passive_deletes\n                if rel_info.link_model:\n                    ins = inspect(rel_info.link_model)\n                    local_table = getattr(ins, \"local_table\")  # noqa: B009\n                    if local_table is None:\n                        raise RuntimeError(\n                            \"Couldn't find the secondary table for \"\n                            f\"model {rel_info.link_model}\"\n                        )\n                    rel_kwargs[\"secondary\"] = local_table\n                rel_args: list[Any] = []\n                if rel_info.sa_relationship_args:\n                    rel_args.extend(rel_info.sa_relationship_args)\n                if rel_info.sa_relationship_kwargs:\n                    rel_kwargs.update(rel_info.sa_relationship_kwargs)\n                rel_value = relationship(relationship_to, *rel_args, **rel_kwargs)\n                setattr(cls, rel_name, rel_value)  # Fix #315\n            # SQLAlchemy no longer uses dict_\n            # Ref: https://github.com/sqlalchemy/sqlalchemy/commit/428ea01f00a9cc7f85e435018565eb6da7af1b77\n            # Tag: 1.4.36\n            DeclarativeMeta.__init__(cls, classname, bases, dict_, **kw)\n        else:\n            ModelMetaclass.__init__(cls, classname, bases, dict_, **kw)\n\n\ndef get_sqlalchemy_type(field: Any) -> Any:\n    field_info = field\n    sa_type = _get_sqlmodel_field_value(field_info, \"sa_type\", Undefined)  # noqa: B009\n    if sa_type is not Undefined:\n        return sa_type\n\n    type_ = get_sa_type_from_field(field)\n    metadata = get_field_metadata(field)\n\n    # Check enums first as an enum can also be a str, needed by Pydantic/FastAPI\n    if issubclass(type_, Enum):\n        return sa_Enum(type_)\n    if issubclass(\n        type_,\n        (\n            str,\n            ipaddress.IPv4Address,\n            ipaddress.IPv4Network,\n            ipaddress.IPv6Address,\n            ipaddress.IPv6Network,\n            Path,\n            EmailStr,\n        ),\n    ):\n        max_length = getattr(metadata, \"max_length\", None)\n        if max_length:\n            return AutoString(length=max_length)\n        return AutoString\n    if issubclass(type_, float):\n        return Float\n    if issubclass(type_, bool):\n        return Boolean\n    if issubclass(type_, int):\n        return Integer\n    if issubclass(type_, datetime):\n        return DateTime\n    if issubclass(type_, date):\n        return Date\n    if issubclass(type_, timedelta):\n        return Interval\n    if issubclass(type_, time):\n        return Time\n    if issubclass(type_, bytes):\n        return LargeBinary\n    if issubclass(type_, Decimal):\n        return Numeric(\n            precision=getattr(metadata, \"max_digits\", None),\n            scale=getattr(metadata, \"decimal_places\", None),\n        )\n    if issubclass(type_, uuid.UUID):\n        return Uuid\n    raise ValueError(f\"{type_} has no matching SQLAlchemy type\")\n\n\ndef get_column_from_field(field: Any) -> Column:  # type: ignore\n    field_info = field\n    sa_column = _get_sqlmodel_field_value(field_info, \"sa_column\", Undefined)\n    if isinstance(sa_column, Column):\n        return sa_column\n    sa_type = get_sqlalchemy_type(field)\n    primary_key = _get_sqlmodel_field_value(field_info, \"primary_key\", Undefined)\n    if primary_key is Undefined:\n        primary_key = False\n    index = _get_sqlmodel_field_value(field_info, \"index\", Undefined)\n    if index is Undefined:\n        index = False\n    nullable = not primary_key and is_field_noneable(field)\n    # Override derived nullability if the nullable property is set explicitly\n    # on the field\n    field_nullable = _get_sqlmodel_field_value(field_info, \"nullable\", Undefined)\n    if field_nullable is not Undefined:\n        assert not isinstance(field_nullable, UndefinedType)\n        nullable = field_nullable\n    args = []\n    foreign_key = _get_sqlmodel_field_value(field_info, \"foreign_key\", Undefined)\n    if foreign_key is Undefined:\n        foreign_key = None\n    unique = _get_sqlmodel_field_value(field_info, \"unique\", Undefined)\n    if unique is Undefined:\n        unique = False\n    if foreign_key:\n        ondelete_value = _get_sqlmodel_field_value(field_info, \"ondelete\", Undefined)\n        if ondelete_value is Undefined:\n            ondelete_value = None\n        if ondelete_value == \"SET NULL\" and not nullable:\n            raise RuntimeError('ondelete=\"SET NULL\" requires nullable=True')\n        assert isinstance(foreign_key, str)\n        assert isinstance(ondelete_value, (str, type(None)))  # for typing\n        args.append(ForeignKey(foreign_key, ondelete=ondelete_value))\n    kwargs = {\n        \"primary_key\": primary_key,\n        \"nullable\": nullable,\n        \"index\": index,\n        \"unique\": unique,\n    }\n    sa_default = Undefined\n    if field_info.default_factory:\n        sa_default = field_info.default_factory\n    elif field_info.default is not Undefined:\n        sa_default = field_info.default\n    if sa_default is not Undefined:\n        kwargs[\"default\"] = sa_default\n    sa_column_args = _get_sqlmodel_field_value(field_info, \"sa_column_args\", Undefined)\n    if sa_column_args is not Undefined:\n        args.extend(list(cast(Sequence[Any], sa_column_args)))\n    sa_column_kwargs = _get_sqlmodel_field_value(\n        field_info, \"sa_column_kwargs\", Undefined\n    )\n    if sa_column_kwargs is not Undefined:\n        kwargs.update(cast(dict[Any, Any], sa_column_kwargs))\n    return Column(sa_type, *args, **kwargs)\n\n\nclass_registry = weakref.WeakValueDictionary()  # type: ignore\n\ndefault_registry = registry()\n\n_TSQLModel = TypeVar(\"_TSQLModel\", bound=\"SQLModel\")\n\n\nclass SQLModel(BaseModel, metaclass=SQLModelMetaclass, registry=default_registry):\n    # SQLAlchemy needs to set weakref(s), Pydantic will set the other slots values\n    __slots__ = (\"__weakref__\",)\n    __tablename__: ClassVar[str | Callable[..., str]]\n    __sqlmodel_relationships__: ClassVar[builtins.dict[str, RelationshipProperty[Any]]]\n    __name__: ClassVar[str]\n    metadata: ClassVar[MetaData]\n    __allow_unmapped__ = True  # https://docs.sqlalchemy.org/en/20/changelog/migration_20.html#migration-20-step-six\n    model_config = SQLModelConfig(from_attributes=True)\n\n    def __new__(cls, *args: Any, **kwargs: Any) -> Any:\n        new_object = super().__new__(cls)\n        # SQLAlchemy doesn't call __init__ on the base class when querying from DB\n        # Ref: https://docs.sqlalchemy.org/en/14/orm/constructors.html\n        # Set __fields_set__ here, that would have been set when calling __init__\n        # in the Pydantic model so that when SQLAlchemy sets attributes that are\n        # added (e.g. when querying from DB) to the __fields_set__, this already exists\n        init_pydantic_private_attrs(new_object)\n        return new_object\n\n    def __init__(__pydantic_self__, **data: Any) -> None:\n        # Uses something other than `self` the first arg to allow \"self\" as a\n        # settable attribute\n\n        # SQLAlchemy does very dark black magic and modifies the __init__ method in\n        # sqlalchemy.orm.instrumentation._generate_init()\n        # so, to make SQLAlchemy work, it's needed to explicitly call __init__ to\n        # trigger all the SQLAlchemy logic, it doesn't work using cls.__new__, setting\n        # attributes obj.__dict__, etc. The __init__ method has to be called. But\n        # there are cases where calling all the default logic is not ideal, e.g.\n        # when calling Model.model_validate(), as the validation is done outside\n        # of instance creation.\n        # At the same time, __init__ is what users would normally call, by creating\n        # a new instance, which should have validation and all the default logic.\n        # So, to be able to set up the internal SQLAlchemy logic alone without\n        # executing the rest, and support things like Model.model_validate(), we\n        # use a contextvar to know if we should execute everything.\n        if finish_init.get():\n            sqlmodel_init(self=__pydantic_self__, data=data)\n\n    def __setattr__(self, name: str, value: Any) -> None:\n        if name in {\"_sa_instance_state\"}:\n            self.__dict__[name] = value\n            return\n        else:\n            # Set in SQLAlchemy, before Pydantic to trigger events and updates\n            if is_table_model_class(self.__class__) and is_instrumented(self, name):  # type: ignore[no-untyped-call]\n                set_attribute(self, name, value)\n            # Set in Pydantic model to trigger possible validation changes, only for\n            # non relationship values\n            if name not in self.__sqlmodel_relationships__:\n                super().__setattr__(name, value)\n\n    def __repr_args__(self) -> Sequence[tuple[str | None, Any]]:\n        # Don't show SQLAlchemy private attributes\n        return [\n            (k, v)\n            for k, v in super().__repr_args__()\n            if not (isinstance(k, str) and k.startswith(\"_sa_\"))\n        ]\n\n    @declared_attr  # type: ignore\n    def __tablename__(cls) -> str:\n        return cls.__name__.lower()\n\n    @classmethod\n    def model_validate(  # type: ignore[override]\n        cls: type[_TSQLModel],\n        obj: Any,\n        *,\n        strict: bool | None = None,\n        from_attributes: bool | None = None,\n        context: builtins.dict[str, Any] | None = None,\n        update: builtins.dict[str, Any] | None = None,\n    ) -> _TSQLModel:\n        return sqlmodel_validate(\n            cls=cls,\n            obj=obj,\n            strict=strict,\n            from_attributes=from_attributes,\n            context=context,\n            update=update,\n        )\n\n    def model_dump(\n        self,\n        *,\n        mode: Literal[\"json\", \"python\"] | str = \"python\",\n        include: IncEx | None = None,\n        exclude: IncEx | None = None,\n        context: Any | None = None,  # v2.7\n        by_alias: bool | None = None,\n        exclude_unset: bool = False,\n        exclude_defaults: bool = False,\n        exclude_none: bool = False,\n        exclude_computed_fields: bool = False,  # v2.12\n        round_trip: bool = False,\n        warnings: bool | Literal[\"none\", \"warn\", \"error\"] = True,\n        fallback: Callable[[Any], Any] | None = None,  # v2.11\n        serialize_as_any: bool = False,  # v2.7\n    ) -> builtins.dict[str, Any]:\n        if PYDANTIC_MINOR_VERSION < (2, 11):\n            by_alias = by_alias or False\n        extra_kwargs: dict[str, Any] = {}\n        extra_kwargs[\"context\"] = context\n        extra_kwargs[\"serialize_as_any\"] = serialize_as_any\n        if PYDANTIC_MINOR_VERSION >= (2, 11):\n            extra_kwargs[\"fallback\"] = fallback\n        if PYDANTIC_MINOR_VERSION >= (2, 12):\n            extra_kwargs[\"exclude_computed_fields\"] = exclude_computed_fields\n        return super().model_dump(\n            mode=mode,\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n            round_trip=round_trip,\n            warnings=warnings,\n            **extra_kwargs,\n        )\n\n    @deprecated(\n        \"\"\"\n        🚨 `obj.dict()` was deprecated in SQLModel 0.0.14, you should\n        instead use `obj.model_dump()`.\n        \"\"\"\n    )\n    def dict(\n        self,\n        *,\n        include: IncEx | None = None,\n        exclude: IncEx | None = None,\n        by_alias: bool = False,\n        exclude_unset: bool = False,\n        exclude_defaults: bool = False,\n        exclude_none: bool = False,\n    ) -> builtins.dict[str, Any]:\n        return self.model_dump(\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n        )\n\n    @classmethod\n    @deprecated(\n        \"\"\"\n        🚨 `obj.from_orm(data)` was deprecated in SQLModel 0.0.14, you should\n        instead use `obj.model_validate(data)`.\n        \"\"\"\n    )\n    def from_orm(\n        cls: type[_TSQLModel],\n        obj: Any,\n        update: builtins.dict[str, Any] | None = None,\n    ) -> _TSQLModel:\n        return cls.model_validate(obj, update=update)\n\n    @classmethod\n    @deprecated(\n        \"\"\"\n        🚨 `obj.parse_obj(data)` was deprecated in SQLModel 0.0.14, you should\n        instead use `obj.model_validate(data)`.\n        \"\"\"\n    )\n    def parse_obj(\n        cls: type[_TSQLModel],\n        obj: Any,\n        update: builtins.dict[str, Any] | None = None,\n    ) -> _TSQLModel:\n        return cls.model_validate(obj, update=update)\n\n    def sqlmodel_update(\n        self: _TSQLModel,\n        obj: builtins.dict[str, Any] | BaseModel,\n        *,\n        update: builtins.dict[str, Any] | None = None,\n    ) -> _TSQLModel:\n        use_update = (update or {}).copy()\n        if isinstance(obj, dict):\n            for key, value in {**obj, **use_update}.items():\n                if key in get_model_fields(self):\n                    setattr(self, key, value)\n        elif isinstance(obj, BaseModel):\n            for key in get_model_fields(obj):\n                if key in use_update:\n                    value = use_update.pop(key)\n                else:\n                    value = getattr(obj, key)\n                setattr(self, key, value)\n            for remaining_key, value in use_update.items():\n                if remaining_key in get_model_fields(self):\n                    setattr(self, remaining_key, value)\n        else:\n            raise ValueError(\n                \"Can't use sqlmodel_update() with something that \"\n                f\"is not a dict or SQLModel or Pydantic model: {obj}\"\n            )\n        return self\n"
  },
  {
    "path": "sqlmodel/orm/__init__.py",
    "content": ""
  },
  {
    "path": "sqlmodel/orm/session.py",
    "content": "from collections.abc import Mapping, Sequence\nfrom typing import (\n    Any,\n    TypeVar,\n    overload,\n)\n\nfrom sqlalchemy import util\nfrom sqlalchemy.engine.cursor import CursorResult\nfrom sqlalchemy.engine.interfaces import _CoreAnyExecuteParams\nfrom sqlalchemy.engine.result import Result, ScalarResult, TupleResult\nfrom sqlalchemy.orm import Query as _Query\nfrom sqlalchemy.orm import Session as _Session\nfrom sqlalchemy.orm._typing import OrmExecuteOptionsParameter\nfrom sqlalchemy.sql._typing import _ColumnsClauseArgument\nfrom sqlalchemy.sql.base import Executable as _Executable\nfrom sqlalchemy.sql.dml import UpdateBase\nfrom sqlmodel.sql.base import Executable\nfrom sqlmodel.sql.expression import Select, SelectOfScalar\nfrom typing_extensions import deprecated\n\n_TSelectParam = TypeVar(\"_TSelectParam\", bound=Any)\n\n\nclass Session(_Session):\n    @overload\n    def exec(\n        self,\n        statement: Select[_TSelectParam],\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> TupleResult[_TSelectParam]: ...\n\n    @overload\n    def exec(\n        self,\n        statement: SelectOfScalar[_TSelectParam],\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> ScalarResult[_TSelectParam]: ...\n\n    @overload\n    def exec(\n        self,\n        statement: UpdateBase,\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> CursorResult[Any]: ...\n\n    def exec(\n        self,\n        statement: Select[_TSelectParam]\n        | SelectOfScalar[_TSelectParam]\n        | Executable[_TSelectParam]\n        | UpdateBase,\n        *,\n        params: Mapping[str, Any] | Sequence[Mapping[str, Any]] | None = None,\n        execution_options: Mapping[str, Any] = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> TupleResult[_TSelectParam] | ScalarResult[_TSelectParam] | CursorResult[Any]:\n        results = super().execute(\n            statement,\n            params=params,\n            execution_options=execution_options,\n            bind_arguments=bind_arguments,\n            _parent_execute_state=_parent_execute_state,\n            _add_event=_add_event,\n        )\n        if isinstance(statement, SelectOfScalar):\n            return results.scalars()\n        return results  # type: ignore\n\n    @deprecated(\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.execute()`.\n\n        This is the original SQLAlchemy `session.execute()` method that returns objects\n        of type `Row`, and that you have to call `scalars()` to get the model objects.\n\n        For example:\n\n        ```Python\n        heroes = session.execute(select(Hero)).scalars().all()\n        ```\n\n        instead you could use `exec()`:\n\n        ```Python\n        heroes = session.exec(select(Hero)).all()\n        ```\n        \"\"\",\n        category=None,\n    )\n    def execute(\n        self,\n        statement: _Executable,\n        params: _CoreAnyExecuteParams | None = None,\n        *,\n        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,\n        bind_arguments: dict[str, Any] | None = None,\n        _parent_execute_state: Any | None = None,\n        _add_event: Any | None = None,\n    ) -> Result[Any]:\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.execute()`.\n\n        This is the original SQLAlchemy `session.execute()` method that returns objects\n        of type `Row`, and that you have to call `scalars()` to get the model objects.\n\n        For example:\n\n        ```Python\n        heroes = session.execute(select(Hero)).scalars().all()\n        ```\n\n        instead you could use `exec()`:\n\n        ```Python\n        heroes = session.exec(select(Hero)).all()\n        ```\n        \"\"\"\n        return super().execute(\n            statement,\n            params=params,\n            execution_options=execution_options,\n            bind_arguments=bind_arguments,\n            _parent_execute_state=_parent_execute_state,\n            _add_event=_add_event,\n        )\n\n    @deprecated(\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.query()`.\n\n        `session.exec()` is SQLModel's own short version with increased type\n        annotations.\n\n        Or otherwise you might want to use `session.execute()` instead of\n        `session.query()`.\n        \"\"\"\n    )\n    def query(  # type: ignore\n        self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any\n    ) -> _Query[Any]:\n        \"\"\"\n        🚨 You probably want to use `session.exec()` instead of `session.query()`.\n\n        `session.exec()` is SQLModel's own short version with increased type\n        annotations.\n\n        Or otherwise you might want to use `session.execute()` instead of\n        `session.query()`.\n        \"\"\"\n        return super().query(*entities, **kwargs)\n"
  },
  {
    "path": "sqlmodel/pool/__init__.py",
    "content": "from sqlalchemy.pool import StaticPool as StaticPool  # noqa: F401\n"
  },
  {
    "path": "sqlmodel/py.typed",
    "content": ""
  },
  {
    "path": "sqlmodel/sql/__init__.py",
    "content": ""
  },
  {
    "path": "sqlmodel/sql/_expression_select_cls.py",
    "content": "from typing import (\n    TypeVar,\n)\n\nfrom sqlalchemy.sql._typing import (\n    _ColumnExpressionArgument,\n)\nfrom sqlalchemy.sql.expression import Select as _Select\nfrom typing_extensions import Self\n\n_T = TypeVar(\"_T\")\n\n\n# Separate this class in SelectBase, Select, and SelectOfScalar so that they can share\n# where and having without having type overlap incompatibility in session.exec().\nclass SelectBase(_Select[tuple[_T]]):\n    inherit_cache = True\n\n    def where(self, *whereclause: _ColumnExpressionArgument[bool] | bool) -> Self:\n        \"\"\"Return a new `Select` construct with the given expression added to\n        its `WHERE` clause, joined to the existing clause via `AND`, if any.\n        \"\"\"\n        return super().where(*whereclause)  # type: ignore[arg-type]\n\n    def having(self, *having: _ColumnExpressionArgument[bool] | bool) -> Self:\n        \"\"\"Return a new `Select` construct with the given expression added to\n        its `HAVING` clause, joined to the existing clause via `AND`, if any.\n        \"\"\"\n        return super().having(*having)  # type: ignore[arg-type]\n\n\nclass Select(SelectBase[_T]):\n    inherit_cache = True\n\n\n# This is not comparable to sqlalchemy.sql.selectable.ScalarSelect, that has a different\n# purpose. This is the same as a normal SQLAlchemy Select class where there's only one\n# entity, so the result will be converted to a scalar by default. This way writing\n# for loops on the results will feel natural.\nclass SelectOfScalar(SelectBase[_T]):\n    inherit_cache = True\n"
  },
  {
    "path": "sqlmodel/sql/_expression_select_gen.py",
    "content": "# WARNING: do not modify this code, it is generated by _expression_select_gen.py.jinja2\n\nfrom collections.abc import Mapping, Sequence\nfrom datetime import datetime\nfrom typing import (\n    Any,\n    TypeVar,\n    overload,\n)\nfrom uuid import UUID\n\nfrom sqlalchemy import (\n    Column,\n)\nfrom sqlalchemy.sql.elements import (\n    SQLCoreOperations,\n)\nfrom sqlalchemy.sql.roles import TypedColumnsClauseRole\n\nfrom ._expression_select_cls import Select, SelectOfScalar\n\n_T = TypeVar(\"_T\")\n\n\n_TCCA = TypedColumnsClauseRole[_T] | SQLCoreOperations[_T] | type[_T]\n\n# Generated TypeVars start\n\n\n_TScalar_0 = TypeVar(\n    \"_TScalar_0\",\n    Column,  # type: ignore\n    Sequence,  # type: ignore\n    Mapping,  # type: ignore\n    UUID,\n    datetime,\n    float,\n    int,\n    bool,\n    bytes,\n    str,\n    None,\n)\n\n_T0 = TypeVar(\"_T0\")\n\n\n_TScalar_1 = TypeVar(\n    \"_TScalar_1\",\n    Column,  # type: ignore\n    Sequence,  # type: ignore\n    Mapping,  # type: ignore\n    UUID,\n    datetime,\n    float,\n    int,\n    bool,\n    bytes,\n    str,\n    None,\n)\n\n_T1 = TypeVar(\"_T1\")\n\n\n_TScalar_2 = TypeVar(\n    \"_TScalar_2\",\n    Column,  # type: ignore\n    Sequence,  # type: ignore\n    Mapping,  # type: ignore\n    UUID,\n    datetime,\n    float,\n    int,\n    bool,\n    bytes,\n    str,\n    None,\n)\n\n_T2 = TypeVar(\"_T2\")\n\n\n_TScalar_3 = TypeVar(\n    \"_TScalar_3\",\n    Column,  # type: ignore\n    Sequence,  # type: ignore\n    Mapping,  # type: ignore\n    UUID,\n    datetime,\n    float,\n    int,\n    bool,\n    bytes,\n    str,\n    None,\n)\n\n_T3 = TypeVar(\"_T3\")\n\n\n# Generated TypeVars end\n\n\n@overload\ndef select(__ent0: _TCCA[_T0]) -> SelectOfScalar[_T0]: ...\n\n\n@overload\ndef select(__ent0: _TScalar_0) -> SelectOfScalar[_TScalar_0]:  # type: ignore\n    ...\n\n\n# Generated overloads start\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n) -> Select[tuple[_T0, _T1]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n) -> Select[tuple[_T0, _TScalar_1]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n) -> Select[tuple[_TScalar_0, _T1]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n) -> Select[tuple[_TScalar_0, _TScalar_1]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n) -> Select[tuple[_T0, _T1, _T2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n) -> Select[tuple[_T0, _T1, _TScalar_2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n) -> Select[tuple[_T0, _TScalar_1, _T2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n) -> Select[tuple[_T0, _TScalar_1, _TScalar_2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n) -> Select[tuple[_TScalar_0, _T1, _T2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n) -> Select[tuple[_TScalar_0, _T1, _TScalar_2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n) -> Select[tuple[_TScalar_0, _TScalar_1, _T2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n) -> Select[tuple[_TScalar_0, _TScalar_1, _TScalar_2]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_T0, _T1, _T2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n    entity_3: _TScalar_3,\n) -> Select[tuple[_T0, _T1, _T2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_T0, _T1, _TScalar_2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n    entity_3: _TScalar_3,\n) -> Select[tuple[_T0, _T1, _TScalar_2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_T0, _TScalar_1, _T2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n    entity_3: _TScalar_3,\n) -> Select[tuple[_T0, _TScalar_1, _T2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_T0, _TScalar_1, _TScalar_2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    __ent0: _TCCA[_T0],\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n    entity_3: _TScalar_3,\n) -> Select[tuple[_T0, _TScalar_1, _TScalar_2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_TScalar_0, _T1, _T2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    __ent2: _TCCA[_T2],\n    entity_3: _TScalar_3,\n) -> Select[tuple[_TScalar_0, _T1, _T2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_TScalar_0, _T1, _TScalar_2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    __ent1: _TCCA[_T1],\n    entity_2: _TScalar_2,\n    entity_3: _TScalar_3,\n) -> Select[tuple[_TScalar_0, _T1, _TScalar_2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_TScalar_0, _TScalar_1, _T2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    __ent2: _TCCA[_T2],\n    entity_3: _TScalar_3,\n) -> Select[tuple[_TScalar_0, _TScalar_1, _T2, _TScalar_3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n    __ent3: _TCCA[_T3],\n) -> Select[tuple[_TScalar_0, _TScalar_1, _TScalar_2, _T3]]: ...\n\n\n@overload\ndef select(  # type: ignore\n    entity_0: _TScalar_0,\n    entity_1: _TScalar_1,\n    entity_2: _TScalar_2,\n    entity_3: _TScalar_3,\n) -> Select[tuple[_TScalar_0, _TScalar_1, _TScalar_2, _TScalar_3]]: ...\n\n\n# Generated overloads end\n\n\ndef select(*entities: Any) -> Select | SelectOfScalar:  # type: ignore\n    if len(entities) == 1:\n        return SelectOfScalar(*entities)\n    return Select(*entities)\n"
  },
  {
    "path": "sqlmodel/sql/_expression_select_gen.py.jinja2",
    "content": "from collections.abc import Mapping, Sequence\nfrom datetime import datetime\nfrom typing import (\n    Any,\n    TypeVar,\n    overload,\n)\nfrom uuid import UUID\n\nfrom sqlalchemy import (\n    Column,\n)\nfrom sqlalchemy.sql.elements import (\n    SQLCoreOperations,\n)\nfrom sqlalchemy.sql.roles import TypedColumnsClauseRole\n\nfrom ._expression_select_cls import Select, SelectOfScalar\n\n_T = TypeVar(\"_T\")\n\n\n_TCCA = TypedColumnsClauseRole[_T] | SQLCoreOperations[_T] | type[_T]\n\n# Generated TypeVars start\n\n\n{% for i in range(number_of_types) %}\n_TScalar_{{ i }} = TypeVar(\n    \"_TScalar_{{ i }}\",\n    Column,  # type: ignore\n    Sequence,  # type: ignore\n    Mapping,  # type: ignore\n    UUID,\n    datetime,\n    float,\n    int,\n    bool,\n    bytes,\n    str,\n    None,\n)\n\n_T{{ i }} = TypeVar(\"_T{{ i }}\")\n\n{% endfor %}\n\n# Generated TypeVars end\n\n@overload\ndef select(__ent0: _TCCA[_T0]) -> SelectOfScalar[_T0]: ...\n\n\n@overload\ndef select(__ent0: _TScalar_0) -> SelectOfScalar[_TScalar_0]:  # type: ignore\n    ...\n\n\n# Generated overloads start\n\n{% for signature in signatures %}\n\n@overload\ndef select(  # type: ignore\n    {% for arg in signature[0] %}{{ arg.name }}: {{ arg.annotation }}, {% endfor %}\n    ) -> Select[tuple[{%for ret in signature[1] %}{{ ret }} {% if not loop.last %}, {% endif %}{% endfor %}]]: ...\n\n{% endfor %}\n\n# Generated overloads end\n\n\ndef select(*entities: Any) -> Select | SelectOfScalar:  # type: ignore\n    if len(entities) == 1:\n        return SelectOfScalar(*entities)\n    return Select(*entities)\n"
  },
  {
    "path": "sqlmodel/sql/base.py",
    "content": "from typing import Generic, TypeVar\n\nfrom sqlalchemy.sql.base import Executable as _Executable\n\n_T = TypeVar(\"_T\")\n\n\nclass Executable(_Executable, Generic[_T]):\n    pass\n"
  },
  {
    "path": "sqlmodel/sql/expression.py",
    "content": "from collections.abc import Iterable, Mapping, Sequence\nfrom typing import (\n    Any,\n    Literal,\n    Optional,\n    TypeVar,\n)\n\nimport sqlalchemy\nfrom sqlalchemy import (\n    Column,\n    ColumnElement,\n    Extract,\n    FunctionElement,\n    FunctionFilter,\n    Label,\n    Over,\n    TypeCoerce,\n    WithinGroup,\n)\nfrom sqlalchemy.orm import InstrumentedAttribute, Mapped\nfrom sqlalchemy.sql._typing import (\n    _ColumnExpressionArgument,\n    _ColumnExpressionOrLiteralArgument,\n    _ColumnExpressionOrStrLabelArgument,\n)\nfrom sqlalchemy.sql.elements import (\n    BinaryExpression,\n    Case,\n    Cast,\n    CollectionAggregate,\n    ColumnClause,\n    TryCast,\n    UnaryExpression,\n)\nfrom sqlalchemy.sql.type_api import TypeEngine\n\nfrom ._expression_select_cls import Select as Select\nfrom ._expression_select_cls import SelectOfScalar as SelectOfScalar\nfrom ._expression_select_gen import select as select\n\n_T = TypeVar(\"_T\")\n\n_TypeEngineArgument = type[TypeEngine[_T]] | TypeEngine[_T]\n\n# Redefine operators that would only take a column expression to also take the (virtual)\n# types of Pydantic models, e.g. str instead of only Mapped[str].\n\n\ndef all_(expr: _ColumnExpressionArgument[_T] | _T) -> CollectionAggregate[bool]:\n    return sqlalchemy.all_(expr)  # type: ignore[arg-type]\n\n\ndef and_(\n    initial_clause: Literal[True] | _ColumnExpressionArgument[bool] | bool,\n    *clauses: _ColumnExpressionArgument[bool] | bool,\n) -> ColumnElement[bool]:\n    return sqlalchemy.and_(initial_clause, *clauses)  # type: ignore[arg-type]\n\n\ndef any_(expr: _ColumnExpressionArgument[_T] | _T) -> CollectionAggregate[bool]:\n    return sqlalchemy.any_(expr)  # type: ignore[arg-type]\n\n\ndef asc(\n    column: _ColumnExpressionOrStrLabelArgument[_T] | _T,\n) -> UnaryExpression[_T]:\n    return sqlalchemy.asc(column)  # type: ignore[arg-type]\n\n\ndef collate(\n    expression: _ColumnExpressionArgument[str] | str, collation: str\n) -> BinaryExpression[str]:\n    return sqlalchemy.collate(expression, collation)  # type: ignore[arg-type]\n\n\ndef between(\n    expr: _ColumnExpressionOrLiteralArgument[_T] | _T,\n    lower_bound: Any,\n    upper_bound: Any,\n    symmetric: bool = False,\n) -> BinaryExpression[bool]:\n    return sqlalchemy.between(expr, lower_bound, upper_bound, symmetric=symmetric)\n\n\ndef not_(clause: _ColumnExpressionArgument[_T] | _T) -> ColumnElement[_T]:\n    return sqlalchemy.not_(clause)  # type: ignore[arg-type]\n\n\ndef case(\n    *whens: tuple[_ColumnExpressionArgument[bool] | bool, Any] | Mapping[Any, Any],\n    value: Any | None = None,\n    else_: Any | None = None,\n) -> Case[Any]:\n    return sqlalchemy.case(*whens, value=value, else_=else_)  # type: ignore[arg-type]\n\n\ndef cast(\n    expression: _ColumnExpressionOrLiteralArgument[Any] | Any,\n    type_: \"_TypeEngineArgument[_T]\",\n) -> Cast[_T]:\n    return sqlalchemy.cast(expression, type_)\n\n\ndef try_cast(\n    expression: _ColumnExpressionOrLiteralArgument[Any] | Any,\n    type_: \"_TypeEngineArgument[_T]\",\n) -> TryCast[_T]:\n    return sqlalchemy.try_cast(expression, type_)\n\n\ndef desc(\n    column: _ColumnExpressionOrStrLabelArgument[_T] | _T,\n) -> UnaryExpression[_T]:\n    return sqlalchemy.desc(column)  # type: ignore[arg-type]\n\n\ndef distinct(expr: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]:\n    return sqlalchemy.distinct(expr)  # type: ignore[arg-type]\n\n\ndef bitwise_not(expr: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]:\n    return sqlalchemy.bitwise_not(expr)  # type: ignore[arg-type]\n\n\ndef extract(field: str, expr: _ColumnExpressionArgument[Any] | Any) -> Extract:\n    return sqlalchemy.extract(field, expr)\n\n\ndef funcfilter(\n    func: FunctionElement[_T], *criterion: _ColumnExpressionArgument[bool] | bool\n) -> FunctionFilter[_T]:\n    return sqlalchemy.funcfilter(func, *criterion)  # type: ignore[arg-type]\n\n\ndef label(\n    name: str,\n    element: _ColumnExpressionArgument[_T] | _T,\n    type_: Optional[\"_TypeEngineArgument[_T]\"] = None,\n) -> Label[_T]:\n    return sqlalchemy.label(name, element, type_=type_)  # type: ignore[arg-type]\n\n\ndef nulls_first(\n    column: _ColumnExpressionArgument[_T] | _T,\n) -> UnaryExpression[_T]:\n    return sqlalchemy.nulls_first(column)  # type: ignore[arg-type]\n\n\ndef nulls_last(column: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]:\n    return sqlalchemy.nulls_last(column)  # type: ignore[arg-type]\n\n\ndef or_(\n    initial_clause: Literal[False] | _ColumnExpressionArgument[bool] | bool,\n    *clauses: _ColumnExpressionArgument[bool] | bool,\n) -> ColumnElement[bool]:\n    return sqlalchemy.or_(initial_clause, *clauses)  # type: ignore[arg-type]\n\n\ndef over(\n    element: FunctionElement[_T],\n    partition_by: Iterable[_ColumnExpressionArgument[Any] | Any]\n    | _ColumnExpressionArgument[Any]\n    | Any\n    | None = None,\n    order_by: Iterable[_ColumnExpressionArgument[Any] | Any]\n    | _ColumnExpressionArgument[Any]\n    | Any\n    | None = None,\n    range_: tuple[int | None, int | None] | None = None,\n    rows: tuple[int | None, int | None] | None = None,\n) -> Over[_T]:\n    return sqlalchemy.over(\n        element, partition_by=partition_by, order_by=order_by, range_=range_, rows=rows\n    )\n\n\ndef tuple_(\n    *clauses: _ColumnExpressionArgument[Any] | Any,\n    types: Sequence[\"_TypeEngineArgument[Any]\"] | None = None,\n) -> sqlalchemy.Tuple:\n    return sqlalchemy.tuple_(*clauses, types=types)\n\n\ndef type_coerce(\n    expression: _ColumnExpressionOrLiteralArgument[Any] | Any,\n    type_: \"_TypeEngineArgument[_T]\",\n) -> TypeCoerce[_T]:\n    return sqlalchemy.type_coerce(expression, type_)\n\n\ndef within_group(\n    element: FunctionElement[_T], *order_by: _ColumnExpressionArgument[Any] | Any\n) -> WithinGroup[_T]:\n    return sqlalchemy.within_group(element, *order_by)\n\n\ndef col(column_expression: _T) -> Mapped[_T]:\n    if not isinstance(column_expression, (ColumnClause, Column, InstrumentedAttribute)):\n        raise RuntimeError(f\"Not a SQLAlchemy column: {column_expression}\")\n    return column_expression  # type: ignore\n"
  },
  {
    "path": "sqlmodel/sql/sqltypes.py",
    "content": "from typing import Any, cast\n\nfrom sqlalchemy import types\nfrom sqlalchemy.engine.interfaces import Dialect\n\n\nclass AutoString(types.TypeDecorator):  # type: ignore\n    impl = types.String\n    cache_ok = True\n    mysql_default_length = 255\n\n    def load_dialect_impl(self, dialect: Dialect) -> \"types.TypeEngine[Any]\":\n        impl = cast(types.String, self.impl)\n        if impl.length is None and dialect.name == \"mysql\":\n            return dialect.type_descriptor(types.String(self.mysql_default_length))\n        return super().load_dialect_impl(dialect)\n"
  },
  {
    "path": "sqlmodel-slim/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://sqlmodel.tiangolo.com\"><img src=\"https://sqlmodel.tiangolo.com/img/logo-margin/logo-margin-vector.svg#only-light\" alt=\"SQLModel\"></a>\n\n</p>\n<p align=\"center\">\n    <em>SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3ATest+event%3Apush+branch%3Amain\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/test.yml/badge.svg?event=push&branch=main\" alt=\"Test\">\n</a>\n<a href=\"https://github.com/fastapi/sqlmodel/actions?query=workflow%3APublish\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/sqlmodel/actions/workflows/publish.yml/badge.svg\" alt=\"Publish\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/sqlmodel\" target=\"_blank\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/sqlmodel.svg\" alt=\"Coverage\">\n<a href=\"https://pypi.org/project/sqlmodel\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/v/sqlmodel?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n</p>\n\n---\n\n**Documentation**: <a href=\"https://sqlmodel.tiangolo.com\" target=\"_blank\">https://sqlmodel.tiangolo.com</a>\n\n**Source Code**: <a href=\"https://github.com/fastapi/sqlmodel\" target=\"_blank\">https://github.com/fastapi/sqlmodel</a>\n\n---\n\nSQLModel is a library for interacting with <abbr title='Also called \"Relational databases\"'>SQL databases</abbr> from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust.\n\n**SQLModel** is based on Python type annotations, and powered by <a href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\">Pydantic</a> and <a href=\"https://sqlalchemy.org/\" class=\"external-link\" target=\"_blank\">SQLAlchemy</a>.\n\n## `sqlmodel-slim`\n\n⚠️ Do not install this package. ⚠️\n\nThis package, `sqlmodel-slim`, does nothing other than depend on `sqlmodel`.\n\nYou **should not** install this package.\n\nInstall instead:\n\n```bash\npip install sqlmodel\n```\n\nThis package is deprecated and will stop receiving any updates and published versions.\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/conftest.py",
    "content": "import shutil\nimport subprocess\nimport sys\nfrom collections.abc import Callable, Generator\nfrom dataclasses import dataclass, field\nfrom pathlib import Path\nfrom typing import Any\nfrom unittest.mock import patch\n\nimport pytest\nfrom pydantic import BaseModel\nfrom sqlmodel import SQLModel\nfrom sqlmodel.main import default_registry\n\ntop_level_path = Path(__file__).resolve().parent.parent\ndocs_src_path = top_level_path / \"docs_src\"\n\n\n@pytest.fixture(autouse=True)\ndef clear_sqlmodel() -> Any:\n    # Clear the tables in the metadata for the default base model\n    SQLModel.metadata.clear()\n    # Clear the Models associated with the registry, to avoid warnings\n    default_registry.dispose()\n    yield\n    SQLModel.metadata.clear()\n    default_registry.dispose()\n\n\n@pytest.fixture()\ndef cov_tmp_path(tmp_path: Path) -> Generator[Path, None, None]:\n    yield tmp_path\n    for coverage_path in tmp_path.glob(\".coverage*\"):\n        coverage_destiny_path = top_level_path / \"coverage\" / coverage_path.name\n        shutil.copy(coverage_path, coverage_destiny_path)\n\n\ndef coverage_run(*, module: str, cwd: str | Path) -> subprocess.CompletedProcess:\n    result = subprocess.run(\n        [\n            \"coverage\",\n            \"run\",\n            \"--parallel-mode\",\n            \"--source=docs_src,tests,sqlmodel\",\n            \"-m\",\n            module,\n        ],\n        cwd=str(cwd),\n        capture_output=True,\n        encoding=\"utf-8\",\n    )\n    return result\n\n\ndef get_testing_print_function(\n    calls: list[list[str | dict[str, Any]]],\n) -> Callable[..., Any]:\n    def new_print(*args: Any) -> None:\n        data: list[Any] = []\n        for arg in args:\n            if isinstance(arg, BaseModel):\n                data.append(arg.model_dump())\n            elif isinstance(arg, list):\n                new_list = []\n                for item in arg:\n                    if isinstance(item, BaseModel):\n                        new_list.append(item.model_dump())\n                data.append(new_list)\n            else:\n                data.append(arg)\n        calls.append(data)\n\n    return new_print\n\n\n@dataclass\nclass PrintMock:\n    calls: list[Any] = field(default_factory=list)\n\n\n@pytest.fixture(name=\"print_mock\")\ndef print_mock_fixture() -> Generator[PrintMock, None, None]:\n    print_mock = PrintMock()\n    new_print = get_testing_print_function(print_mock.calls)\n    with patch(\"builtins.print\", new=new_print):\n        yield print_mock\n\n\nneeds_py310 = pytest.mark.skipif(\n    sys.version_info < (3, 10), reason=\"requires python3.10+\"\n)\n"
  },
  {
    "path": "tests/test_advanced/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_advanced/test_decimal/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_advanced/test_decimal/test_tutorial001.py",
    "content": "import importlib\nfrom decimal import Decimal\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.advanced.decimal.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Hero 1:\",\n        {\n            \"name\": \"Deadpond\",\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"money\": Decimal(\"1.100\"),\n        },\n    ],\n    [\n        \"Hero 2:\",\n        {\n            \"name\": \"Rusty-Man\",\n            \"age\": 48,\n            \"id\": 3,\n            \"secret_name\": \"Tommy Sharp\",\n            \"money\": Decimal(\"2.200\"),\n        },\n    ],\n    [\"Total money: 3.300\"],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_advanced/test_uuid/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_advanced/test_uuid/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsUUID\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.advanced.uuid.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType) -> None:\n    mod.main()\n    first_uuid = print_mock.calls[1][0][\"id\"]\n    assert first_uuid == IsUUID(4)\n\n    second_uuid = print_mock.calls[7][0][\"id\"]\n    assert second_uuid == IsUUID(4)\n\n    assert first_uuid != second_uuid\n\n    assert print_mock.calls == [\n        [\"The hero before saving in the DB\"],\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"id\": first_uuid,\n                \"age\": None,\n            }\n        ],\n        [\"The hero ID was already set\"],\n        [first_uuid],\n        [\"After saving in the DB\"],\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"age\": None,\n                \"id\": first_uuid,\n            }\n        ],\n        [\"Created hero:\"],\n        [\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"id\": second_uuid,\n            }\n        ],\n        [\"Created hero ID:\"],\n        [second_uuid],\n        [\"Selected hero:\"],\n        [\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"id\": second_uuid,\n            }\n        ],\n        [\"Selected hero ID:\"],\n        [second_uuid],\n    ]\n"
  },
  {
    "path": "tests/test_advanced/test_uuid/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsUUID\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.advanced.uuid.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType) -> None:\n    mod.main()\n    first_uuid = print_mock.calls[1][0][\"id\"]\n    assert first_uuid == IsUUID(4)\n\n    second_uuid = print_mock.calls[7][0][\"id\"]\n    assert second_uuid == IsUUID(4)\n\n    assert first_uuid != second_uuid\n\n    assert print_mock.calls == [\n        [\"The hero before saving in the DB\"],\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"id\": first_uuid,\n                \"age\": None,\n            }\n        ],\n        [\"The hero ID was already set\"],\n        [first_uuid],\n        [\"After saving in the DB\"],\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"age\": None,\n                \"id\": first_uuid,\n            }\n        ],\n        [\"Created hero:\"],\n        [\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"id\": second_uuid,\n            }\n        ],\n        [\"Created hero ID:\"],\n        [second_uuid],\n        [\"Selected hero:\"],\n        [\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"id\": second_uuid,\n            }\n        ],\n        [\"Selected hero ID:\"],\n        [second_uuid],\n    ]\n"
  },
  {
    "path": "tests/test_aliases.py",
    "content": "import pytest\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic import Field as PField\nfrom sqlmodel import Field, SQLModel\n\n\"\"\"\nAlias tests for SQLModel and Pydantic compatibility\n\"\"\"\n\n\nclass PydanticUser(BaseModel):\n    full_name: str = PField(alias=\"fullName\")\n\n\nclass SQLModelUser(SQLModel):\n    full_name: str = Field(alias=\"fullName\")\n\n\n# Models with config (validate_by_name=True)\nclass PydanticUserWithConfig(PydanticUser):\n    model_config = {\"validate_by_name\": True}\n\n\nclass SQLModelUserWithConfig(SQLModelUser):\n    model_config = {\"validate_by_name\": True}\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUser, SQLModelUser])\ndef test_create_with_field_name(model: type[PydanticUser] | type[SQLModelUser]):\n    with pytest.raises(ValidationError):\n        model(full_name=\"Alice\")\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUserWithConfig, SQLModelUserWithConfig])\ndef test_create_with_field_name_with_config(\n    model: type[PydanticUserWithConfig] | type[SQLModelUserWithConfig],\n):\n    user = model(full_name=\"Alice\")\n    assert user.full_name == \"Alice\"\n\n\n@pytest.mark.parametrize(\n    \"model\",\n    [PydanticUser, SQLModelUser, PydanticUserWithConfig, SQLModelUserWithConfig],\n)\ndef test_create_with_alias(\n    model: type[PydanticUser]\n    | type[SQLModelUser]\n    | type[PydanticUserWithConfig]\n    | type[SQLModelUserWithConfig],\n):\n    user = model(fullName=\"Bob\")  # using alias\n    assert user.full_name == \"Bob\"\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUserWithConfig, SQLModelUserWithConfig])\ndef test_create_with_both_prefers_alias(\n    model: type[PydanticUserWithConfig] | type[SQLModelUserWithConfig],\n):\n    user = model(full_name=\"IGNORED\", fullName=\"Charlie\")\n    assert user.full_name == \"Charlie\"  # alias should take precedence\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUser, SQLModelUser])\ndef test_dict_default_uses_field_names(\n    model: type[PydanticUser] | type[SQLModelUser],\n):\n    user = model(fullName=\"Dana\")\n    data = user.model_dump()\n    assert \"full_name\" in data\n    assert \"fullName\" not in data\n    assert data[\"full_name\"] == \"Dana\"\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUser, SQLModelUser])\ndef test_dict_by_alias_uses_aliases(\n    model: type[PydanticUser] | type[SQLModelUser],\n):\n    user = model(fullName=\"Dana\")\n    data = user.model_dump(by_alias=True)\n    assert \"fullName\" in data\n    assert \"full_name\" not in data\n    assert data[\"fullName\"] == \"Dana\"\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUser, SQLModelUser])\ndef test_json_by_alias(\n    model: type[PydanticUser] | type[SQLModelUser],\n):\n    user = model(fullName=\"Frank\")\n    json_data = user.model_dump_json(by_alias=True)\n    assert ('\"fullName\":\"Frank\"' in json_data) or ('\"fullName\": \"Frank\"' in json_data)\n    assert \"full_name\" not in json_data\n\n\nclass PydanticUserV2(BaseModel):\n    first_name: str = PField(validation_alias=\"firstName\", serialization_alias=\"f_name\")\n\n\nclass SQLModelUserV2(SQLModel):\n    first_name: str = Field(validation_alias=\"firstName\", serialization_alias=\"f_name\")\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUserV2, SQLModelUserV2])\ndef test_create_with_validation_alias(\n    model: type[PydanticUserV2] | type[SQLModelUserV2],\n):\n    user = model(firstName=\"John\")\n    assert user.first_name == \"John\"\n\n\n@pytest.mark.parametrize(\"model\", [PydanticUserV2, SQLModelUserV2])\ndef test_serialize_with_serialization_alias(\n    model: type[PydanticUserV2] | type[SQLModelUserV2],\n):\n    user = model(firstName=\"Jane\")\n    data = user.model_dump(by_alias=True)\n    assert \"f_name\" in data\n    assert \"firstName\" not in data\n    assert \"first_name\" not in data\n    assert data[\"f_name\"] == \"Jane\"\n\n\ndef test_schema_extra_validation_alias_sqlmodel_v2():\n    class M(SQLModel):\n        f: str = Field(schema_extra={\"validation_alias\": \"f_alias\"})\n\n    m = M.model_validate({\"f_alias\": \"asd\"})\n    assert m.f == \"asd\"\n\n\ndef test_schema_extra_serialization_alias_sqlmodel_v2():\n    class M(SQLModel):\n        f: str = Field(schema_extra={\"serialization_alias\": \"f_out\"})\n\n    m = M(f=\"x\")\n    data = m.model_dump(by_alias=True)\n    assert \"f_out\" in data\n    assert \"f\" not in data\n    assert data[\"f_out\"] == \"x\"\n\n\ndef test_alias_plus_validation_alias_prefers_validation_alias_sqlmodel_v2():\n    class M(SQLModel):\n        first_name: str = Field(alias=\"fullName\", validation_alias=\"v_name\")\n\n    m = M.model_validate({\"fullName\": \"A\", \"v_name\": \"B\"})\n    assert m.first_name == \"B\"\n\n\ndef test_alias_plus_serialization_alias_prefers_serialization_alias_sqlmodel_v2():\n    class M(SQLModel):\n        first_name: str = Field(alias=\"fullName\", serialization_alias=\"f_name\")\n\n    m = M(fullName=\"Z\")\n    data = m.model_dump(by_alias=True)\n    assert \"f_name\" in data\n    assert \"fullName\" not in data\n    assert data[\"f_name\"] == \"Z\"\n\n\ndef test_alias_generator_works_sqlmodel_v2():\n    class M(SQLModel):\n        model_config = {\"alias_generator\": lambda s: \"gen_\" + s}\n        f: str = Field()\n\n    m = M.model_validate({\"gen_f\": \"ok\"})\n    assert m.f == \"ok\"\n    data = m.model_dump(by_alias=True)\n    assert \"gen_f\" in data and data[\"gen_f\"] == \"ok\"\n\n\ndef test_alias_generator_with_explicit_alias_prefers_field_alias_sqlmodel_v2():\n    class M(SQLModel):\n        model_config = {\"alias_generator\": lambda s: \"gen_\" + s}\n        f: str = Field(alias=\"custom\")\n\n    m = M.model_validate({\"custom\": \"ok\"})\n    assert m.f == \"ok\"\n    data = m.model_dump(by_alias=True)\n    assert \"custom\" in data and \"gen_f\" not in data\n"
  },
  {
    "path": "tests/test_annotated_uuid.py",
    "content": "import uuid\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\ndef test_annotated_optional_types(clear_sqlmodel) -> None:\n    from pydantic import UUID4\n\n    class Hero(SQLModel, table=True):\n        # Pydantic UUID4 is: Annotated[UUID, UuidVersion(4)]\n        id: UUID4 | None = Field(default_factory=uuid.uuid4, primary_key=True)\n\n    engine = create_engine(\"sqlite:///:memory:\")\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as db:\n        hero = Hero()\n        db.add(hero)\n        db.commit()\n        statement = select(Hero)\n        result = db.exec(statement).all()\n    assert len(result) == 1\n    assert isinstance(hero.id, uuid.UUID)\n"
  },
  {
    "path": "tests/test_default.py",
    "content": "from sqlmodel.default import Default\n\n\ndef test_default_bool() -> None:\n    dt1 = Default(True)\n    dt2 = Default(1)\n    dt3 = Default(\"foo\")\n    dt4 = Default([\"foo\"])\n    df1 = Default(False)\n    df2 = Default(0)\n    df3 = Default(\"\")\n    df4: list = Default([])\n    df5 = Default(None)\n\n    assert not not dt1\n    assert not not dt2\n    assert not not dt3\n    assert not not dt4\n    assert not df1\n    assert not df2\n    assert not df3\n    assert not df4\n    assert not df5\n\n\ndef test_equality() -> None:\n    value1 = Default(\"foo\")\n    value2 = Default(\"foo\")\n\n    assert value1 == value2\n\n\ndef test_not_equality() -> None:\n    value1 = Default(\"foo\")\n    value2 = Default(\"bar\")\n\n    assert not (value1 == value2)\n\n\ndef test_not_equality_other() -> None:\n    value1 = Default(\"foo\")\n    value2 = \"foo\"\n\n    assert not (value1 == value2)\n"
  },
  {
    "path": "tests/test_deprecations.py",
    "content": "import pytest\nfrom sqlmodel import SQLModel\n\n\nclass Item(SQLModel):\n    name: str\n\n\nclass SubItem(Item):\n    password: str\n\n\ndef test_deprecated_from_orm_inheritance():\n    new_item = SubItem(name=\"Hello\", password=\"secret\")\n    with pytest.warns(DeprecationWarning):\n        item = Item.from_orm(new_item)\n    assert item.name == \"Hello\"\n    assert not hasattr(item, \"password\")\n\n\ndef test_deprecated_parse_obj():\n    with pytest.warns(DeprecationWarning):\n        item = Item.parse_obj({\"name\": \"Hello\"})\n    assert item.name == \"Hello\"\n\n\ndef test_deprecated_dict():\n    with pytest.warns(DeprecationWarning):\n        data = Item(name=\"Hello\").dict()\n    assert data == {\"name\": \"Hello\"}\n"
  },
  {
    "path": "tests/test_enums.py",
    "content": "import importlib\n\nimport pytest\nfrom sqlalchemy import create_mock_engine\nfrom sqlalchemy.sql.type_api import TypeEngine\nfrom sqlmodel import SQLModel\n\nfrom . import test_enums_models\n\n\"\"\"\nTests related to Enums\n\nAssociated issues:\n* https://github.com/tiangolo/sqlmodel/issues/96\n* https://github.com/tiangolo/sqlmodel/issues/164\n\"\"\"\n\n\ndef pg_dump(sql: TypeEngine, *args, **kwargs):\n    dialect = sql.compile(dialect=postgres_engine.dialect)\n    sql_str = str(dialect).rstrip()\n    if sql_str:\n        print(sql_str + \";\")\n\n\ndef sqlite_dump(sql: TypeEngine, *args, **kwargs):\n    dialect = sql.compile(dialect=sqlite_engine.dialect)\n    sql_str = str(dialect).rstrip()\n    if sql_str:\n        print(sql_str + \";\")\n\n\npostgres_engine = create_mock_engine(\"postgresql://\", pg_dump)\nsqlite_engine = create_mock_engine(\"sqlite://\", sqlite_dump)\n\n\ndef test_postgres_ddl_sql(clear_sqlmodel, capsys: pytest.CaptureFixture[str]):\n    assert test_enums_models, \"Ensure the models are imported and registered\"\n    importlib.reload(test_enums_models)\n    SQLModel.metadata.create_all(bind=postgres_engine, checkfirst=False)\n\n    captured = capsys.readouterr()\n    assert \"CREATE TYPE myenum1 AS ENUM ('A', 'B');\" in captured.out\n    assert \"CREATE TYPE myenum2 AS ENUM ('C', 'D');\" in captured.out\n\n\ndef test_sqlite_ddl_sql(clear_sqlmodel, capsys: pytest.CaptureFixture[str]):\n    assert test_enums_models, \"Ensure the models are imported and registered\"\n    importlib.reload(test_enums_models)\n    SQLModel.metadata.create_all(bind=sqlite_engine, checkfirst=False)\n\n    captured = capsys.readouterr()\n    assert \"enum_field VARCHAR(1) NOT NULL\" in captured.out, captured\n    assert \"CREATE TYPE\" not in captured.out\n\n\ndef test_json_schema_flat_model_pydantic_v2():\n    assert test_enums_models.FlatModel.model_json_schema() == {\n        \"title\": \"FlatModel\",\n        \"type\": \"object\",\n        \"properties\": {\n            \"id\": {\"title\": \"Id\", \"type\": \"string\", \"format\": \"uuid\"},\n            \"enum_field\": {\"$ref\": \"#/$defs/MyEnum1\"},\n        },\n        \"required\": [\"id\", \"enum_field\"],\n        \"$defs\": {\n            \"MyEnum1\": {\"enum\": [\"A\", \"B\"], \"title\": \"MyEnum1\", \"type\": \"string\"}\n        },\n    }\n\n\ndef test_json_schema_inherit_model_pydantic_v2():\n    assert test_enums_models.InheritModel.model_json_schema() == {\n        \"title\": \"InheritModel\",\n        \"type\": \"object\",\n        \"properties\": {\n            \"id\": {\"title\": \"Id\", \"type\": \"string\", \"format\": \"uuid\"},\n            \"enum_field\": {\"$ref\": \"#/$defs/MyEnum2\"},\n        },\n        \"required\": [\"id\", \"enum_field\"],\n        \"$defs\": {\n            \"MyEnum2\": {\"enum\": [\"C\", \"D\"], \"title\": \"MyEnum2\", \"type\": \"string\"}\n        },\n    }\n"
  },
  {
    "path": "tests/test_enums_models.py",
    "content": "import enum\nimport uuid\n\nfrom sqlmodel import Field, SQLModel\n\n\nclass MyEnum1(str, enum.Enum):\n    A = \"A\"\n    B = \"B\"\n\n\nclass MyEnum2(str, enum.Enum):\n    C = \"C\"\n    D = \"D\"\n\n\nclass BaseModel(SQLModel):\n    id: uuid.UUID = Field(primary_key=True)\n    enum_field: MyEnum2\n\n\nclass FlatModel(SQLModel, table=True):\n    id: uuid.UUID = Field(primary_key=True)\n    enum_field: MyEnum1\n\n\nclass InheritModel(BaseModel, table=True):\n    pass\n"
  },
  {
    "path": "tests/test_field_sa_args_kwargs.py",
    "content": "from sqlalchemy import ForeignKey\nfrom sqlmodel import Field, SQLModel, create_engine\n\n\ndef test_sa_column_args(clear_sqlmodel, caplog) -> None:\n    class Team(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n\n    class Hero(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        team_id: int | None = Field(\n            default=None,\n            sa_column_args=[ForeignKey(\"team.id\")],\n        )\n\n    engine = create_engine(\"sqlite://\", echo=True)\n    SQLModel.metadata.create_all(engine)\n    create_table_log = [\n        message for message in caplog.messages if \"CREATE TABLE hero\" in message\n    ][0]\n    assert \"FOREIGN KEY(team_id) REFERENCES team (id)\" in create_table_log\n\n\ndef test_sa_column_kargs(clear_sqlmodel, caplog) -> None:\n    class Item(SQLModel, table=True):\n        id: int | None = Field(\n            default=None,\n            sa_column_kwargs={\"primary_key\": True},\n        )\n\n    engine = create_engine(\"sqlite://\", echo=True)\n    SQLModel.metadata.create_all(engine)\n    create_table_log = [\n        message for message in caplog.messages if \"CREATE TABLE item\" in message\n    ][0]\n    assert \"PRIMARY KEY (id)\" in create_table_log\n"
  },
  {
    "path": "tests/test_field_sa_column.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom sqlalchemy import Column, Integer, String\nfrom sqlmodel import Field, SQLModel\n\n\ndef test_sa_column_takes_precedence() -> None:\n    class Item(SQLModel, table=True):\n        id: int | None = Field(\n            default=None,\n            sa_column=Column(String, primary_key=True, nullable=False),\n        )\n\n    # It would have been nullable with no sa_column\n    assert Item.id.nullable is False  # type: ignore\n    assert isinstance(Item.id.type, String)  # type: ignore\n\n\ndef test_sa_column_with_annotated_metadata() -> None:\n    class Item(SQLModel, table=True):\n        id: Annotated[int | None, \"meta\"] = Field(\n            default=None,\n            sa_column=Column(String, primary_key=True, nullable=False),\n        )\n\n    assert Item.id.nullable is False  # type: ignore\n    assert isinstance(Item.id.type, String)  # type: ignore\n\n\ndef test_sa_column_no_sa_args() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                sa_column_args=[Integer],\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_sa_kargs() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                sa_column_kwargs={\"primary_key\": True},\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_type() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                sa_type=Integer,\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_primary_key() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                primary_key=True,\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_nullable() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                nullable=True,\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_foreign_key() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Team(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            team_id: int | None = Field(\n                default=None,\n                foreign_key=\"team.id\",\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_unique() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                unique=True,\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_index() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                index=True,\n                sa_column=Column(Integer, primary_key=True),\n            )\n\n\ndef test_sa_column_no_ondelete() -> None:\n    with pytest.raises(RuntimeError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(\n                default=None,\n                sa_column=Column(Integer, primary_key=True),\n                ondelete=\"CASCADE\",\n            )\n"
  },
  {
    "path": "tests/test_field_sa_relationship.py",
    "content": "import pytest\nfrom sqlalchemy.orm import relationship\nfrom sqlmodel import Field, Relationship, SQLModel\n\n\ndef test_sa_relationship_no_args() -> None:\n    with pytest.raises(RuntimeError):  # pragma: no cover\n\n        class Team(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str = Field(index=True)\n            headquarters: str\n\n            heroes: list[\"Hero\"] = Relationship(\n                back_populates=\"team\",\n                sa_relationship_args=[\"Hero\"],\n                sa_relationship=relationship(\"Hero\", back_populates=\"team\"),\n            )\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str = Field(index=True)\n            secret_name: str\n            age: int | None = Field(default=None, index=True)\n\n            team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n            team: Team | None = Relationship(back_populates=\"heroes\")\n\n\ndef test_sa_relationship_no_kwargs() -> None:\n    with pytest.raises(RuntimeError):  # pragma: no cover\n\n        class Team(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str = Field(index=True)\n            headquarters: str\n\n            heroes: list[\"Hero\"] = Relationship(\n                back_populates=\"team\",\n                sa_relationship_kwargs={\"lazy\": \"selectin\"},\n                sa_relationship=relationship(\"Hero\", back_populates=\"team\"),\n            )\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str = Field(index=True)\n            secret_name: str\n            age: int | None = Field(default=None, index=True)\n\n            team_id: int | None = Field(default=None, foreign_key=\"team.id\")\n            team: Team | None = Relationship(back_populates=\"heroes\")\n"
  },
  {
    "path": "tests/test_fields_set.py",
    "content": "from datetime import datetime, timedelta\n\nfrom sqlmodel import Field, SQLModel\n\n\ndef test_fields_set():\n    class User(SQLModel):\n        username: str\n        email: str = \"test@test.com\"\n        last_updated: datetime = Field(default_factory=datetime.now)\n\n    user = User(username=\"bob\")\n    assert user.model_fields_set == {\"username\"}\n    user = User(username=\"bob\", email=\"bob@test.com\")\n    assert user.model_fields_set == {\"username\", \"email\"}\n    user = User(\n        username=\"bob\",\n        email=\"bob@test.com\",\n        last_updated=datetime.now() - timedelta(days=1),\n    )\n    assert user.model_fields_set == {\"username\", \"email\", \"last_updated\"}\n"
  },
  {
    "path": "tests/test_future_annotations.py",
    "content": "from __future__ import annotations\n\nfrom typing import Annotated\n\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\ndef test_model_with_future_annotations(clear_sqlmodel):\n    class Hero(SQLModel, table=True):\n        id: Annotated[int | None, Field(primary_key=True)] = None\n        name: str\n        secret_name: str\n        age: int | None = None\n\n    hero = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\", age=25)\n\n    engine = create_engine(\"sqlite://\")\n    SQLModel.metadata.create_all(engine)\n\n    with Session(engine) as session:\n        session.add(hero)\n        session.commit()\n        session.refresh(hero)\n\n        assert hero.id is not None\n        assert hero.name == \"Deadpond\"\n        assert hero.secret_name == \"Dive Wilson\"\n        assert hero.age == 25\n\n    with Session(engine) as session:\n        heroes = session.exec(select(Hero)).all()\n        assert len(heroes) == 1\n        assert heroes[0].name == \"Deadpond\"\n\n\ndef test_model_with_string_annotations(clear_sqlmodel):\n    class Team(SQLModel, table=True):\n        id: Annotated[int | None, Field(primary_key=True)] = None\n        name: str\n\n    class Player(SQLModel, table=True):\n        id: Annotated[int | None, Field(primary_key=True)] = None\n        name: str\n        team_id: Annotated[int | None, Field(foreign_key=\"team.id\")] = None\n\n    engine = create_engine(\"sqlite://\")\n    SQLModel.metadata.create_all(engine)\n\n    team = Team(name=\"Champions\")\n    player = Player(name=\"Alice\", team_id=None)\n\n    with Session(engine) as session:\n        session.add(team)\n        session.commit()\n        session.refresh(team)\n\n        player.team_id = team.id\n        session.add(player)\n        session.commit()\n        session.refresh(player)\n\n        assert team.id is not None\n        assert player.team_id == team.id\n"
  },
  {
    "path": "tests/test_instance_no_args.py",
    "content": "import pytest\nfrom pydantic import ValidationError\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\ndef test_allow_instantiation_without_arguments(clear_sqlmodel):\n    class Item(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n        description: str | None = None\n\n    engine = create_engine(\"sqlite:///:memory:\")\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as db:\n        item = Item()\n        item.name = \"Rick\"\n        db.add(item)\n        db.commit()\n        statement = select(Item)\n        result = db.exec(statement).all()\n    assert len(result) == 1\n    assert isinstance(item.id, int)\n    SQLModel.metadata.clear()\n\n\ndef test_not_allow_instantiation_without_arguments_if_not_table():\n    class Item(SQLModel):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n        description: str | None = None\n\n    with pytest.raises(ValidationError):\n        Item()\n"
  },
  {
    "path": "tests/test_main.py",
    "content": "from typing import Annotated\r\n\r\nimport pytest\r\nfrom sqlalchemy.exc import IntegrityError\r\nfrom sqlalchemy.orm import RelationshipProperty\r\nfrom sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select\r\n\r\n\r\ndef test_should_allow_duplicate_row_if_unique_constraint_is_not_passed(clear_sqlmodel):\r\n    class Hero(SQLModel, table=True):\r\n        id: int | None = Field(default=None, primary_key=True)\r\n        name: str\r\n        secret_name: str\r\n        age: int | None = None\r\n\r\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n    hero_2 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_1)\r\n        session.commit()\r\n        session.refresh(hero_1)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_2)\r\n        session.commit()\r\n        session.refresh(hero_2)\r\n\r\n    with Session(engine) as session:\r\n        heroes = session.exec(select(Hero)).all()\r\n        assert len(heroes) == 2\r\n        assert heroes[0].name == heroes[1].name\r\n\r\n\r\ndef test_should_allow_duplicate_row_if_unique_constraint_is_false(clear_sqlmodel):\r\n    class Hero(SQLModel, table=True):\r\n        id: int | None = Field(default=None, primary_key=True)\r\n        name: str\r\n        secret_name: str = Field(unique=False)\r\n        age: int | None = None\r\n\r\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n    hero_2 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_1)\r\n        session.commit()\r\n        session.refresh(hero_1)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_2)\r\n        session.commit()\r\n        session.refresh(hero_2)\r\n\r\n    with Session(engine) as session:\r\n        heroes = session.exec(select(Hero)).all()\r\n        assert len(heroes) == 2\r\n        assert heroes[0].name == heroes[1].name\r\n\r\n\r\ndef test_should_raise_exception_when_try_to_duplicate_row_if_unique_constraint_is_true(\r\n    clear_sqlmodel,\r\n):\r\n    class Hero(SQLModel, table=True):\r\n        id: int | None = Field(default=None, primary_key=True)\r\n        name: str\r\n        secret_name: str = Field(unique=True)\r\n        age: int | None = None\r\n\r\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n    hero_2 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_1)\r\n        session.commit()\r\n        session.refresh(hero_1)\r\n\r\n    with pytest.raises(IntegrityError):\r\n        with Session(engine) as session:\r\n            session.add(hero_2)\r\n            session.commit()\r\n\r\n\r\ndef test_sa_relationship_property(clear_sqlmodel):\r\n    \"\"\"Test https://github.com/tiangolo/sqlmodel/issues/315#issuecomment-1272122306\"\"\"\r\n\r\n    class Team(SQLModel, table=True):\r\n        id: int | None = Field(default=None, primary_key=True)\r\n        name: str = Field(unique=True)\r\n        heroes: list[\"Hero\"] = Relationship(  # noqa: F821\r\n            sa_relationship=RelationshipProperty(\"Hero\", back_populates=\"team\")\r\n        )\r\n\r\n    class Hero(SQLModel, table=True):\r\n        id: int | None = Field(default=None, primary_key=True)\r\n        name: str = Field(unique=True)\r\n        team_id: int | None = Field(default=None, foreign_key=\"team.id\")\r\n        team: Team | None = Relationship(\r\n            sa_relationship=RelationshipProperty(\"Team\", back_populates=\"heroes\")\r\n        )\r\n\r\n    team_preventers = Team(name=\"Preventers\")\r\n    hero_rusty_man = Hero(name=\"Rusty-Man\", team=team_preventers)\r\n\r\n    engine = create_engine(\"sqlite://\", echo=True)\r\n\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    with Session(engine) as session:\r\n        session.add(hero_rusty_man)\r\n        session.commit()\r\n        session.refresh(hero_rusty_man)\r\n        # The next statement should not raise an AttributeError\r\n        assert hero_rusty_man.team\r\n        assert hero_rusty_man.team.name == \"Preventers\"\r\n\r\n\r\ndef test_composite_primary_key(clear_sqlmodel):\r\n    class UserPermission(SQLModel, table=True):\r\n        user_id: int = Field(primary_key=True)\r\n        resource_id: int = Field(primary_key=True)\r\n        permission: str\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    pk_column_names = {column.name for column in UserPermission.__table__.primary_key}\r\n    assert pk_column_names == {\"user_id\", \"resource_id\"}\r\n\r\n    with Session(engine) as session:\r\n        perm1 = UserPermission(user_id=1, resource_id=1, permission=\"read\")\r\n        perm2 = UserPermission(user_id=1, resource_id=2, permission=\"write\")\r\n        session.add(perm1)\r\n        session.add(perm2)\r\n        session.commit()\r\n\r\n    with pytest.raises(IntegrityError):\r\n        with Session(engine) as session:\r\n            perm3 = UserPermission(user_id=1, resource_id=1, permission=\"admin\")\r\n            session.add(perm3)\r\n            session.commit()\r\n\r\n\r\ndef test_composite_primary_key_and_validator(clear_sqlmodel):\r\n    from pydantic import AfterValidator\r\n\r\n    def validate_resource_id(value: int) -> int:\r\n        if value < 1:\r\n            raise ValueError(\"Resource ID must be positive\")\r\n        return value\r\n\r\n    class UserPermission(SQLModel, table=True):\r\n        user_id: int = Field(primary_key=True)\r\n        resource_id: Annotated[int, AfterValidator(validate_resource_id)] = Field(\r\n            primary_key=True\r\n        )\r\n        permission: str\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    pk_column_names = {column.name for column in UserPermission.__table__.primary_key}\r\n    assert pk_column_names == {\"user_id\", \"resource_id\"}\r\n\r\n    with Session(engine) as session:\r\n        perm1 = UserPermission(user_id=1, resource_id=1, permission=\"read\")\r\n        perm2 = UserPermission(user_id=1, resource_id=2, permission=\"write\")\r\n        session.add(perm1)\r\n        session.add(perm2)\r\n        session.commit()\r\n\r\n    with pytest.raises(IntegrityError):\r\n        with Session(engine) as session:\r\n            perm3 = UserPermission(user_id=1, resource_id=1, permission=\"admin\")\r\n            session.add(perm3)\r\n            session.commit()\r\n\r\n\r\ndef test_foreign_key_ondelete_with_annotated(clear_sqlmodel):\r\n    from pydantic import AfterValidator\r\n\r\n    def ensure_positive(value: int) -> int:\r\n        if value < 0:\r\n            raise ValueError(\"Team ID must be positive\")\r\n        return value\r\n\r\n    class Team(SQLModel, table=True):\r\n        id: int = Field(primary_key=True)\r\n        name: str\r\n\r\n    class Hero(SQLModel, table=True):\r\n        id: int = Field(primary_key=True)\r\n        team_id: Annotated[int, AfterValidator(ensure_positive)] = Field(\r\n            foreign_key=\"team.id\",\r\n            ondelete=\"CASCADE\",\r\n        )\r\n        name: str\r\n\r\n    engine = create_engine(\"sqlite://\")\r\n    SQLModel.metadata.create_all(engine)\r\n\r\n    team_id_column = Hero.__table__.c.team_id  # type: ignore[attr-defined]\r\n    foreign_keys = list(team_id_column.foreign_keys)\r\n    assert len(foreign_keys) == 1\r\n    assert foreign_keys[0].ondelete == \"CASCADE\"\r\n    assert team_id_column.nullable is False\r\n"
  },
  {
    "path": "tests/test_missing_type.py",
    "content": "import pytest\nfrom pydantic import BaseModel\nfrom sqlmodel import Field, SQLModel\n\n\ndef test_missing_sql_type():\n    class CustomType(BaseModel):\n        @classmethod\n        def __get_validators__(cls):\n            yield cls.validate\n\n        @classmethod\n        def validate(cls, v):  # pragma: no cover\n            return v\n\n    with pytest.raises(ValueError):\n\n        class Item(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            item: CustomType\n"
  },
  {
    "path": "tests/test_nullable.py",
    "content": "import pytest\nfrom sqlalchemy.exc import IntegrityError\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\n\ndef test_nullable_fields(clear_sqlmodel, caplog):\n    class Hero(SQLModel, table=True):\n        primary_key: int | None = Field(\n            default=None,\n            primary_key=True,\n        )\n        required_value: str\n        optional_default_ellipsis: str | None = Field(default=...)\n        optional_default_none: str | None = Field(default=None)\n        optional_non_nullable: str | None = Field(\n            nullable=False,\n        )\n        optional_nullable: str | None = Field(\n            nullable=True,\n        )\n        optional_default_ellipses_non_nullable: str | None = Field(\n            default=...,\n            nullable=False,\n        )\n        optional_default_ellipses_nullable: str | None = Field(\n            default=...,\n            nullable=True,\n        )\n        optional_default_none_non_nullable: str | None = Field(\n            default=None,\n            nullable=False,\n        )\n        optional_default_none_nullable: str | None = Field(\n            default=None,\n            nullable=True,\n        )\n        default_ellipses_non_nullable: str = Field(default=..., nullable=False)\n        optional_default_str: str | None = \"default\"\n        optional_default_str_non_nullable: str | None = Field(\n            default=\"default\", nullable=False\n        )\n        optional_default_str_nullable: str | None = Field(\n            default=\"default\", nullable=True\n        )\n        str_default_str: str = \"default\"\n        str_default_str_non_nullable: str = Field(default=\"default\", nullable=False)\n        str_default_str_nullable: str = Field(default=\"default\", nullable=True)\n        str_default_ellipsis_non_nullable: str = Field(default=..., nullable=False)\n        str_default_ellipsis_nullable: str = Field(default=..., nullable=True)\n\n    engine = create_engine(\"sqlite://\", echo=True)\n    SQLModel.metadata.create_all(engine)\n\n    create_table_log = [\n        message for message in caplog.messages if \"CREATE TABLE hero\" in message\n    ][0]\n    assert \"primary_key INTEGER NOT NULL,\" in create_table_log\n    assert \"required_value VARCHAR NOT NULL,\" in create_table_log\n    assert \"optional_default_ellipsis VARCHAR,\" in create_table_log\n    assert \"optional_default_none VARCHAR,\" in create_table_log\n    assert \"optional_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"optional_nullable VARCHAR,\" in create_table_log\n    assert (\n        \"optional_default_ellipses_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    )\n    assert \"optional_default_ellipses_nullable VARCHAR,\" in create_table_log\n    assert \"optional_default_none_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"optional_default_none_nullable VARCHAR,\" in create_table_log\n    assert \"default_ellipses_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"optional_default_str VARCHAR,\" in create_table_log\n    assert \"optional_default_str_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"optional_default_str_nullable VARCHAR,\" in create_table_log\n    assert \"str_default_str VARCHAR NOT NULL,\" in create_table_log\n    assert \"str_default_str_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"str_default_str_nullable VARCHAR,\" in create_table_log\n    assert \"str_default_ellipsis_non_nullable VARCHAR NOT NULL,\" in create_table_log\n    assert \"str_default_ellipsis_nullable VARCHAR,\" in create_table_log\n\n\n# Test for regression in https://github.com/tiangolo/sqlmodel/issues/420\ndef test_non_nullable_optional_field_with_no_default_set(clear_sqlmodel, caplog):\n    class Hero(SQLModel, table=True):\n        primary_key: int | None = Field(\n            default=None,\n            primary_key=True,\n        )\n\n        optional_non_nullable_no_default: str | None = Field(nullable=False)\n\n    engine = create_engine(\"sqlite://\", echo=True)\n    SQLModel.metadata.create_all(engine)\n\n    create_table_log = [\n        message for message in caplog.messages if \"CREATE TABLE hero\" in message\n    ][0]\n    assert \"primary_key INTEGER NOT NULL,\" in create_table_log\n    assert \"optional_non_nullable_no_default VARCHAR NOT NULL,\" in create_table_log\n\n    # We can create a hero with `None` set for the optional non-nullable field\n    hero = Hero(primary_key=123, optional_non_nullable_no_default=None)\n    # But we cannot commit it.\n    with Session(engine) as session:\n        session.add(hero)\n        with pytest.raises(IntegrityError):\n            session.commit()\n\n\ndef test_nullable_primary_key(clear_sqlmodel, caplog):\n    # Probably the weirdest corner case, it shouldn't happen anywhere, but let's test it\n    class Hero(SQLModel, table=True):\n        nullable_integer_primary_key: int | None = Field(\n            default=None,\n            primary_key=True,\n            nullable=True,\n        )\n\n    engine = create_engine(\"sqlite://\", echo=True)\n    SQLModel.metadata.create_all(engine)\n\n    create_table_log = [\n        message for message in caplog.messages if \"CREATE TABLE hero\" in message\n    ][0]\n    assert \"nullable_integer_primary_key INTEGER,\" in create_table_log\n"
  },
  {
    "path": "tests/test_ondelete_raises.py",
    "content": "from typing import Any\n\nimport pytest\nfrom sqlmodel import Field, Relationship, SQLModel\n\n\ndef test_ondelete_requires_nullable(clear_sqlmodel: Any) -> None:\n    with pytest.raises(RuntimeError) as exc:\n\n        class Team(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n\n            heroes: list[\"Hero\"] = Relationship(\n                back_populates=\"team\", passive_deletes=\"all\"\n            )\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            name: str = Field(index=True)\n            secret_name: str\n            age: int | None = Field(default=None, index=True)\n\n            team_id: int = Field(foreign_key=\"team.id\", ondelete=\"SET NULL\")\n            team: Team = Relationship(back_populates=\"heroes\")\n\n    assert 'ondelete=\"SET NULL\" requires nullable=True' in str(exc.value)\n\n\ndef test_ondelete_requires_foreign_key(clear_sqlmodel: Any) -> None:\n    with pytest.raises(RuntimeError) as exc:\n\n        class Team(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n\n            age: int = Field(ondelete=\"CASCADE\")\n\n    assert \"ondelete can only be used with foreign_key\" in str(exc.value)\n"
  },
  {
    "path": "tests/test_pydantic/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_pydantic/test_field.py",
    "content": "from decimal import Decimal\nfrom typing import Literal\n\nimport pytest\nfrom pydantic import ValidationError\nfrom sqlmodel import Field, SQLModel\n\n\ndef test_decimal():\n    class Model(SQLModel):\n        dec: Decimal = Field(max_digits=4, decimal_places=2)\n\n    Model(dec=Decimal(\"3.14\"))\n    Model(dec=Decimal(\"69.42\"))\n\n    with pytest.raises(ValidationError):\n        Model(dec=Decimal(\"3.142\"))\n    with pytest.raises(ValidationError):\n        Model(dec=Decimal(\"0.069\"))\n    with pytest.raises(ValidationError):\n        Model(dec=Decimal(\"420\"))\n\n\ndef test_discriminator():\n    # Example adapted from\n    # [Pydantic docs](https://pydantic-docs.helpmanual.io/usage/types/#discriminated-unions-aka-tagged-unions):\n\n    class Cat(SQLModel):\n        pet_type: Literal[\"cat\"]\n        meows: int\n\n    class Dog(SQLModel):\n        pet_type: Literal[\"dog\"]\n        barks: float\n\n    class Lizard(SQLModel):\n        pet_type: Literal[\"reptile\", \"lizard\"]\n        scales: bool\n\n    class Model(SQLModel):\n        pet: Cat | Dog | Lizard = Field(..., discriminator=\"pet_type\")\n        n: int\n\n    Model(pet={\"pet_type\": \"dog\", \"barks\": 3.14}, n=1)  # type: ignore[arg-type]\n\n    with pytest.raises(ValidationError):\n        Model(pet={\"pet_type\": \"dog\"}, n=1)  # type: ignore[arg-type]\n\n\ndef test_repr():\n    class Model(SQLModel):\n        id: int | None = Field(primary_key=True)\n        foo: str = Field(repr=False)\n\n    instance = Model(id=123, foo=\"bar\")\n    assert \"foo=\" not in repr(instance)\n"
  },
  {
    "path": "tests/test_query.py",
    "content": "import pytest\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\n\ndef test_query(clear_sqlmodel):\n    class Hero(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n        secret_name: str\n        age: int | None = None\n\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n\n    engine = create_engine(\"sqlite://\")\n\n    SQLModel.metadata.create_all(engine)\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.commit()\n        session.refresh(hero_1)\n\n    with Session(engine) as session:\n        with pytest.warns(DeprecationWarning):\n            query_hero = session.query(Hero).first()\n        assert query_hero\n        assert query_hero.name == hero_1.name\n"
  },
  {
    "path": "tests/test_select_gen.py",
    "content": "import os\nimport subprocess\nimport sys\nfrom pathlib import Path\n\nroot_path = Path(__file__).parent.parent\n\n\ndef test_select_gen() -> None:\n    env = os.environ.copy()\n    env[\"CHECK_JINJA\"] = \"1\"\n    result = subprocess.run(\n        [sys.executable, Path(\"scripts\") / \"generate_select.py\"],\n        env=env,\n        check=True,\n        cwd=root_path,\n        capture_output=True,\n    )\n    print(result.stdout)\n"
  },
  {
    "path": "tests/test_select_typing.py",
    "content": "from sqlmodel import Field, Session, SQLModel, create_engine, select\nfrom sqlmodel.pool import StaticPool\n\n\ndef test_fields() -> None:\n    class Hero(SQLModel, table=True):\n        id: int | None = Field(default=None, primary_key=True)\n        name: str\n        secret_name: str\n        age: int | None = None\n        food: str | None = None\n\n    engine = create_engine(\n        \"sqlite://\", connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n\n    SQLModel.metadata.create_all(engine)\n\n    with Session(engine) as session:\n        session.add(Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\"))\n        session.add(\n            Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\", food=\"pizza\")\n        )\n        session.add(Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48))\n\n        session.commit()\n\n    # check typing of select with 3 fields\n    with Session(engine) as session:\n        statement_3 = select(Hero.id, Hero.name, Hero.secret_name)\n        results_3 = session.exec(statement_3)\n        for hero_3 in results_3:\n            assert len(hero_3) == 3\n            name_3: str = hero_3[1]\n            assert type(name_3) is str\n            assert type(hero_3[0]) is int\n            assert type(hero_3[2]) is str\n\n    # check typing of select with 4 fields\n    with Session(engine) as session:\n        statement_4 = select(Hero.id, Hero.name, Hero.secret_name, Hero.age)\n        results_4 = session.exec(statement_4)\n        for hero_4 in results_4:\n            assert len(hero_4) == 4\n            name_4: str = hero_4[1]\n            assert type(name_4) is str\n            assert type(hero_4[0]) is int\n            assert type(hero_4[2]) is str\n            assert type(hero_4[3]) in [int, type(None)]\n\n    # check typing of select with 5 fields: currently runs but doesn't pass mypy\n    # with Session(engine) as session:\n    #     statement_5 = select(Hero.id, Hero.name, Hero.secret_name, Hero.age, Hero.food)\n    #     results_5 = session.exec(statement_5)\n    #     for hero_5 in results_5:\n    #         assert len(hero_5) == 5\n    #         name_5: str = hero_5[1]\n    #         assert type(name_5) is str\n    #         assert type(hero_5[0]) is int\n    #         assert type(hero_5[2]) is str\n    #         assert type(hero_5[3]) in [int, type(None)]\n    #         assert type(hero_5[4]) in [str, type(None)]\n"
  },
  {
    "path": "tests/test_sqlalchemy_type_errors.py",
    "content": "from typing import Any\n\nimport pytest\nfrom sqlmodel import Field, SQLModel\n\n\ndef test_type_list_breaks() -> None:\n    with pytest.raises(ValueError):\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            tags: list[str]\n\n\ndef test_type_dict_breaks() -> None:\n    with pytest.raises(ValueError):\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            tags: dict[str, Any]\n\n\ndef test_type_union_breaks() -> None:\n    with pytest.raises(ValueError):\n\n        class Hero(SQLModel, table=True):\n            id: int | None = Field(default=None, primary_key=True)\n            tags: int | str\n"
  },
  {
    "path": "tests/test_tutorial/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_automatic_id_none_refresh/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_automatic_id_none_refresh/test_tutorial001_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom typing import Any\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom tests.conftest import PrintMock, needs_py310\n\n\ndef check_calls(calls: list[list[str | dict[str, Any]]]) -> None:\n    assert calls[0] == [\"Before interacting with the database\"]\n    assert calls[1] == [\n        \"Hero 1:\",\n        {\n            \"id\": None,\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"age\": None,\n        },\n    ]\n    assert calls[2] == [\n        \"Hero 2:\",\n        {\n            \"id\": None,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n        },\n    ]\n    assert calls[3] == [\n        \"Hero 3:\",\n        {\n            \"id\": None,\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        },\n    ]\n    assert calls[4] == [\"After adding to the session\"]\n    assert calls[5] == [\n        \"Hero 1:\",\n        {\n            \"id\": None,\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"age\": None,\n        },\n    ]\n    assert calls[6] == [\n        \"Hero 2:\",\n        {\n            \"id\": None,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n        },\n    ]\n    assert calls[7] == [\n        \"Hero 3:\",\n        {\n            \"id\": None,\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        },\n    ]\n    assert calls[8] == [\"After committing the session\"]\n    assert calls[9] == [\"Hero 1:\", {}]\n    assert calls[10] == [\"Hero 2:\", {}]\n    assert calls[11] == [\"Hero 3:\", {}]\n    assert calls[12] == [\"After committing the session, show IDs\"]\n    assert calls[13] == [\"Hero 1 ID:\", 1]\n    assert calls[14] == [\"Hero 2 ID:\", 2]\n    assert calls[15] == [\"Hero 3 ID:\", 3]\n    assert calls[16] == [\"After committing the session, show names\"]\n    assert calls[17] == [\"Hero 1 name:\", \"Deadpond\"]\n    assert calls[18] == [\"Hero 2 name:\", \"Spider-Boy\"]\n    assert calls[19] == [\"Hero 3 name:\", \"Rusty-Man\"]\n    assert calls[20] == [\"After refreshing the heroes\"]\n    assert calls[21] == [\n        \"Hero 1:\",\n        {\n            \"id\": 1,\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"age\": None,\n        },\n    ]\n    assert calls[22] == [\n        \"Hero 2:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n        },\n    ]\n    assert calls[23] == [\n        \"Hero 3:\",\n        {\n            \"id\": 3,\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        },\n    ]\n    assert calls[24] == [\"After the session closes\"]\n    assert calls[21] == [\n        \"Hero 1:\",\n        {\n            \"id\": 1,\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"age\": None,\n        },\n    ]\n    assert calls[22] == [\n        \"Hero 2:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n        },\n    ]\n    assert calls[23] == [\n        \"Hero 3:\",\n        {\n            \"id\": 3,\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        },\n    ]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.automatic_id_none_refresh.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n\n    return module\n\n\ndef test_tutorial_001_tutorial_002(print_mock: PrintMock, module: ModuleType) -> None:\n    module.main()\n    check_calls(print_mock.calls)\n"
  },
  {
    "path": "tests/test_tutorial/test_code_structure/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_code_structure/test_tutorial001.py",
    "content": "import importlib\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom tests.conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"id\": 1,\n            \"name\": \"Deadpond\",\n            \"age\": None,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n        },\n    ],\n    [\n        \"Hero's team:\",\n        {\"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\", \"id\": 1},\n    ],\n]\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    database: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules(request: pytest.FixtureRequest) -> Modules:\n    app_module = importlib.import_module(\n        f\"docs_src.tutorial.code_structure.{request.param}.app\"\n    )\n    database_module = importlib.import_module(\n        f\"docs_src.tutorial.code_structure.{request.param}.database\"\n    )\n    database_module.sqlite_url = \"sqlite://\"\n    database_module.engine = create_engine(database_module.sqlite_url)\n    app_module.engine = database_module.engine\n\n    return Modules(app=app_module, database=database_module)\n\n\ndef test_tutorial(print_mock: PrintMock, modules: Modules):\n    modules.app.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_code_structure/test_tutorial002.py",
    "content": "import importlib\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"id\": 1,\n            \"name\": \"Deadpond\",\n            \"age\": None,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n        },\n    ],\n    [\n        \"Hero's team:\",\n        {\"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\", \"id\": 1},\n    ],\n]\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    database: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules(request: pytest.FixtureRequest) -> Modules:\n    app_module = importlib.import_module(\n        f\"docs_src.tutorial.code_structure.{request.param}.app\"\n    )\n    database_module = importlib.import_module(\n        f\"docs_src.tutorial.code_structure.{request.param}.database\"\n    )\n    database_module.sqlite_url = \"sqlite://\"\n    database_module.engine = create_engine(database_module.sqlite_url)\n    app_module.engine = database_module.engine\n\n    return Modules(app=app_module, database=database_module)\n\n\ndef test_tutorial(print_mock: PrintMock, modules: Modules):\n    modules.app.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_create_connected_tables/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_create_connected_tables/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.create_tables.{request.param}\"\n    )\n    return module\n\n\ndef test_tutorial001(module: ModuleType):\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    module.main()\n    insp: Inspector = inspect(module.engine)\n    assert insp.has_table(str(module.Hero.__tablename__))\n    assert insp.has_table(str(module.Team.__tablename__))\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_delete/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_delete/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 1,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"No longer Preventer:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.delete.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_insert/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_insert/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.insert.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial001(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_select/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_select/test_tutorial001_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n        \"Team:\",\n        {\"id\": 2, \"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"},\n    ],\n    [\n        \"Hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n        \"Team:\",\n        {\"id\": 1, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n    ],\n]\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.select.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial001(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial002(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_select/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n        \"Team:\",\n        {\"id\": 2, \"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"},\n    ],\n    [\n        \"Hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n        \"Team:\",\n        {\"id\": 1, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n    ],\n    [\n        \"Hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n        \"Team:\",\n        None,\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.select.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_select/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventer Hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.select.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_select/test_tutorial005.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventer Hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n        \"Team:\",\n        {\"id\": 1, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.select.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_connect/test_update/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_connect/test_update/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 2,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 1,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 1,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n]\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.connect.update.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_tutorial(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_create_db_and_table/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_create_db_and_table/test_tutorial001.py",
    "content": "from pathlib import Path\n\nimport pytest\n\nfrom ...conftest import coverage_run, needs_py310\n\n\n@pytest.mark.parametrize(\n    \"module_name\",\n    [\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef test_create_db_and_table(cov_tmp_path: Path, module_name: str):\n    module = f\"docs_src.tutorial.create_db_and_table.{module_name}\"\n    result = coverage_run(module=module, cwd=cov_tmp_path)\n    assert \"BEGIN\" in result.stdout\n    assert 'PRAGMA main.table_info(\"hero\")' in result.stdout\n    assert \"CREATE TABLE hero (\" in result.stdout\n    assert \"id INTEGER NOT NULL,\" in result.stdout\n    assert \"name VARCHAR NOT NULL,\" in result.stdout\n    assert \"secret_name VARCHAR NOT NULL,\" in result.stdout\n    assert \"age INTEGER,\" in result.stdout\n    assert \"PRIMARY KEY (id)\" in result.stdout\n    assert \")\" in result.stdout\n    assert \"COMMIT\" in result.stdout\n"
  },
  {
    "path": "tests/test_tutorial/test_create_db_and_table/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom ...conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.create_db_and_table.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_create_db_and_table(module: ModuleType):\n    module.create_db_and_tables()\n    insp: Inspector = inspect(module.engine)\n    assert insp.has_table(str(module.Hero.__tablename__))\n"
  },
  {
    "path": "tests/test_tutorial/test_create_db_and_table/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom ...conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.create_db_and_table.{request.param}\"\n    )\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\ndef test_create_db_and_table(module: ModuleType):\n    module.create_db_and_tables()\n    insp: Inspector = inspect(module.engine)\n    assert insp.has_table(str(module.Hero.__tablename__))\n"
  },
  {
    "path": "tests/test_tutorial/test_delete/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_delete/test_tutorial001_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Hero 1:\",\n        {\"id\": 2, \"name\": \"Spider-Boy\", \"secret_name\": \"Pedro Parqueador\", \"age\": None},\n    ],\n    [\n        \"Hero 2:\",\n        {\n            \"id\": 7,\n            \"name\": \"Captain North America\",\n            \"secret_name\": \"Esteban Rogelios\",\n            \"age\": 93,\n        },\n    ],\n    [\n        \"Updated hero 1:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Youngster\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": 16,\n        },\n    ],\n    [\n        \"Updated hero 2:\",\n        {\n            \"id\": 7,\n            \"name\": \"Captain North America Except Canada\",\n            \"secret_name\": \"Esteban Rogelios\",\n            \"age\": 110,\n        },\n    ],\n    [\n        \"Hero: \",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Youngster\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": 16,\n        },\n    ],\n    [\n        \"Deleted hero:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Youngster\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": 16,\n        },\n    ],\n    [\"There's no hero named Spider-Youngster\"],\n]\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(f\"docs_src.tutorial.delete.{request.param}\")\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial001(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial002(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests001.py",
    "content": "import importlib\nimport sys\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\n\nfrom tests.conftest import needs_py310\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    test: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules_path\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules_path(request: pytest.FixtureRequest) -> str:\n    return f\"docs_src.tutorial.fastapi.app_testing.{request.param}\"\n\n\n@pytest.fixture(name=\"modules\")\ndef load_modules(clear_sqlmodel, modules_path: str) -> Modules:\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel\n    app_mod_path = f\"{modules_path}.main\"\n    if app_mod_path in sys.modules:\n        app_mod = sys.modules[app_mod_path]\n        importlib.reload(app_mod)\n    else:\n        app_mod = importlib.import_module(app_mod_path)\n    test_mod = importlib.import_module(f\"{modules_path}.test_main_001\")\n    return Modules(app=app_mod, test=test_mod)\n\n\ndef test_tutorial(modules: Modules):\n    modules.test.test_create_hero()\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests002.py",
    "content": "import importlib\nimport sys\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\n\nfrom tests.conftest import needs_py310\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    test: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules_path\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules_path(request: pytest.FixtureRequest) -> str:\n    return f\"docs_src.tutorial.fastapi.app_testing.{request.param}\"\n\n\n@pytest.fixture(name=\"modules\")\ndef load_modules(clear_sqlmodel, modules_path: str) -> Modules:\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel\n    app_mod_path = f\"{modules_path}.main\"\n    if app_mod_path in sys.modules:\n        app_mod = sys.modules[app_mod_path]\n        importlib.reload(app_mod)\n    else:\n        app_mod = importlib.import_module(app_mod_path)  # pragma: no cover\n    test_mod = importlib.import_module(f\"{modules_path}.test_main_002\")\n    return Modules(app=app_mod, test=test_mod)\n\n\ndef test_tutorial(modules: Modules):\n    modules.test.test_create_hero()\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests003.py",
    "content": "import importlib\nimport sys\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\n\nfrom tests.conftest import needs_py310\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    test: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules_path\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules_path(request: pytest.FixtureRequest) -> str:\n    return f\"docs_src.tutorial.fastapi.app_testing.{request.param}\"\n\n\n@pytest.fixture(name=\"modules\")\ndef load_modules(clear_sqlmodel, modules_path: str) -> Modules:\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel\n    app_mod_path = f\"{modules_path}.main\"\n    if app_mod_path in sys.modules:\n        app_mod = sys.modules[app_mod_path]\n        importlib.reload(app_mod)\n    else:\n        app_mod = importlib.import_module(app_mod_path)  # pragma: no cover\n    test_mod = importlib.import_module(f\"{modules_path}.test_main_003\")\n    return Modules(app=app_mod, test=test_mod)\n\n\ndef test_tutorial(modules: Modules):\n    modules.test.test_create_hero()\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests004.py",
    "content": "import importlib\nimport sys\nfrom dataclasses import dataclass\nfrom types import ModuleType\n\nimport pytest\n\nfrom tests.conftest import needs_py310\n\n\n@dataclass\nclass Modules:\n    app: ModuleType\n    test: ModuleType\n\n\n@pytest.fixture(\n    name=\"modules_path\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_modules_path(request: pytest.FixtureRequest) -> str:\n    return f\"docs_src.tutorial.fastapi.app_testing.{request.param}\"\n\n\n@pytest.fixture(name=\"modules\")\ndef load_modules(clear_sqlmodel, modules_path: str) -> Modules:\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel\n    app_mod_path = f\"{modules_path}.main\"\n    if app_mod_path in sys.modules:\n        app_mod = sys.modules[app_mod_path]\n        importlib.reload(app_mod)\n    else:\n        app_mod = importlib.import_module(app_mod_path)  # pragma: no cover\n    test_mod = importlib.import_module(f\"{modules_path}.test_main_004\")\n    return Modules(app=app_mod, test=test_mod)\n\n\ndef test_tutorial(modules: Modules):\n    modules.test.test_create_hero()\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests005.py",
    "content": "import importlib\n\nimport pytest\nfrom sqlmodel import Session\n\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310 import main as app_mod\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310 import (\n    test_main_005 as test_mod,\n)\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310.test_main_005 import (\n    session_fixture,\n)\n\nassert session_fixture, \"This keeps the session fixture used below\"\n\n\n@pytest.fixture(name=\"prepare\")\ndef prepare_fixture(clear_sqlmodel):\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel, but before the session_fixture\n    # That's why the extra custom fixture here\n    importlib.reload(app_mod)\n\n\ndef test_tutorial(prepare, session: Session):\n    test_mod.test_create_hero(session)\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import Session\n\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310 import main as app_mod\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310 import (\n    test_main_006 as test_mod,\n)\nfrom docs_src.tutorial.fastapi.app_testing.tutorial001_py310.test_main_006 import (\n    client_fixture,\n    session_fixture,\n)\n\nassert session_fixture, \"This keeps the session fixture used below\"\nassert client_fixture, \"This keeps the client fixture used below\"\n\n\n@pytest.fixture(name=\"prepare\")\ndef prepare_fixture(clear_sqlmodel):\n    # Trigger side effects of registering table models in SQLModel\n    # This has to be called after clear_sqlmodel, but before the session_fixture\n    # That's why the extra custom fixture here\n    importlib.reload(app_mod)\n\n\ndef test_tutorial(prepare, session: Session, client: TestClient):\n    test_mod.test_create_hero(client)\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_app_testing/test_tutorial001_tests_main.py",
    "content": "import importlib\nimport subprocess\nfrom pathlib import Path\nfrom types import ModuleType\n\nimport pytest\n\nfrom ....conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.app_testing.{request.param}.test_main\"\n    )\n    return module\n\n\ndef test_run_tests(module: ModuleType):\n    test_path = Path(module.__file__).resolve().parent\n    top_level_path = Path(__file__).resolve().parent.parent.parent.parent.parent\n    result = subprocess.run(\n        [\n            \"coverage\",\n            \"run\",\n            \"--parallel-mode\",\n            \"-m\",\n            \"pytest\",\n            test_path,\n        ],\n        cwd=top_level_path,\n        capture_output=True,\n    )\n    assert result.returncode == 0, result.stdout.decode(\"utf-8\")\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_delete/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.fastapi.delete.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        response = client.get(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        assert response.status_code == 200, response.text\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n\n        response = client.delete(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n\n        response = client.delete(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"secret_name\": {\n                                \"title\": \"Secret Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_limit_and_offset/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.limit_and_offset.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n\n        response = client.get(\"/heroes/\", params={\"limit\": 2})\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n        assert data[0][\"name\"] == hero1_data[\"name\"]\n        assert data[1][\"name\"] == hero2_data[\"name\"]\n\n        response = client.get(\"/heroes/\", params={\"offset\": 1})\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n        assert data[0][\"name\"] == hero2_data[\"name\"]\n        assert data[1][\"name\"] == hero3_data[\"name\"]\n\n        response = client.get(\"/heroes/\", params={\"offset\": 1, \"limit\": 1})\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 1\n        assert data[0][\"name\"] == hero2_data[\"name\"]\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_multiple_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.multiple_models.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero1_data[\"name\"]\n        assert data[\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[\"id\"] is not None\n        assert data[\"age\"] is None\n\n        response = client.post(\"/heroes/\", json=hero2_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero2_data[\"name\"]\n        assert data[\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[\"id\"] != hero2_data[\"id\"], (\n            \"Now it's not possible to predefine the ID from the request, \"\n            \"it's now set by the database\"\n        )\n        assert data[\"age\"] is None\n\n        response = client.get(\"/heroes/\")\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert len(data) == 2\n        assert data[0][\"name\"] == hero1_data[\"name\"]\n        assert data[0][\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[1][\"name\"] == hero2_data[\"name\"]\n        assert data[1][\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[1][\"id\"] != hero2_data[\"id\"]\n\n        response = client.get(\"/openapi.json\")\n\n        assert response.status_code == 200, response.text\n\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"id\", \"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n\n    # Test inherited indexes\n    insp: Inspector = inspect(module.engine)\n    indexes = insp.get_indexes(str(module.Hero.__tablename__))\n    expected_indexes = [\n        {\n            \"name\": \"ix_hero_name\",\n            \"dialect_options\": {},\n            \"column_names\": [\"name\"],\n            \"unique\": 0,\n        },\n        {\n            \"name\": \"ix_hero_age\",\n            \"dialect_options\": {},\n            \"column_names\": [\"age\"],\n            \"unique\": 0,\n        },\n    ]\n    for index in expected_indexes:\n        assert index in indexes, \"This expected index should be in the indexes in DB\"\n        # Now that this index was checked, remove it from the list of indexes\n        indexes.pop(indexes.index(index))\n    assert len(indexes) == 0, \"The database should only have the expected indexes\"\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.multiple_models.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero1_data[\"name\"]\n        assert data[\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[\"id\"] is not None\n        assert data[\"age\"] is None\n\n        response = client.post(\"/heroes/\", json=hero2_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero2_data[\"name\"]\n        assert data[\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[\"id\"] != hero2_data[\"id\"], (\n            \"Now it's not possible to predefine the ID from the request, \"\n            \"it's now set by the database\"\n        )\n        assert data[\"age\"] is None\n\n        response = client.get(\"/heroes/\")\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert len(data) == 2\n        assert data[0][\"name\"] == hero1_data[\"name\"]\n        assert data[0][\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[1][\"name\"] == hero2_data[\"name\"]\n        assert data[1][\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[1][\"id\"] != hero2_data[\"id\"]\n\n        response = client.get(\"/openapi.json\")\n\n        assert response.status_code == 200, response.text\n\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n\n    # Test inherited indexes\n    insp: Inspector = inspect(module.engine)\n    indexes = insp.get_indexes(str(module.Hero.__tablename__))\n    expected_indexes = [\n        {\n            \"name\": \"ix_hero_age\",\n            \"dialect_options\": {},\n            \"column_names\": [\"age\"],\n            \"unique\": 0,\n        },\n        {\n            \"name\": \"ix_hero_name\",\n            \"dialect_options\": {},\n            \"column_names\": [\"name\"],\n            \"unique\": 0,\n        },\n    ]\n    for index in expected_indexes:\n        assert index in indexes, \"This expected index should be in the indexes in DB\"\n        # Now that this index was checked, remove it from the list of indexes\n        indexes.pop(indexes.index(index))\n    assert len(indexes) == 0, \"The database should only have the expected indexes\"\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_read_one/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.fastapi.read_one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n\n        hero_id = hero2[\"id\"]\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert data == hero2\n\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/openapi.json\")\n\n        assert response.status_code == 200, response.text\n\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        team_preventers = {\"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}\n        team_z_force = {\"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"}\n        response = client.post(\"/teams/\", json=team_preventers)\n        assert response.status_code == 200, response.text\n        team_preventers_data = response.json()\n        team_preventers_id = team_preventers_data[\"id\"]\n        response = client.post(\"/teams/\", json=team_z_force)\n        assert response.status_code == 200, response.text\n        team_z_force_data = response.json()\n        team_z_force_id = team_z_force_data[\"id\"]\n        response = client.get(\"/teams/\")\n        data = response.json()\n        assert len(data) == 2\n        response = client.get(\"/teams/9000\")\n        assert response.status_code == 404, response.text\n        response = client.patch(\n            f\"/teams/{team_preventers_id}\", json={\"headquarters\": \"Preventers Tower\"}\n        )\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == team_preventers[\"name\"]\n        assert data[\"headquarters\"] == \"Preventers Tower\"\n        response = client.patch(\"/teams/9000\", json={\"name\": \"Freedom League\"})\n        assert response.status_code == 404, response.text\n\n        hero1_data = {\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": team_z_force_id,\n        }\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n            \"team_id\": team_preventers_id,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        hero1 = response.json()\n        hero1_id = hero1[\"id\"]\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n        response = client.get(f\"/heroes/{hero1_id}\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert data[\"name\"] == hero1_data[\"name\"]\n        assert data[\"team\"][\"name\"] == team_z_force[\"name\"]\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        assert response.status_code == 200, response.text\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n        response = client.delete(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n        response = client.delete(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        response = client.get(f\"/teams/{team_preventers_id}\")\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == team_preventers_data[\"name\"]\n        assert data[\"heroes\"][0][\"name\"] == hero3_data[\"name\"]\n\n        response = client.delete(f\"/teams/{team_preventers_id}\")\n        assert response.status_code == 200, response.text\n        response = client.delete(\"/teams/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/teams/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 1\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublicWithTeam\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/teams/\": {\n                    \"get\": {\n                        \"summary\": \"Read Teams\",\n                        \"operationId\": \"read_teams_teams__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Teams Teams  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/TeamPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Team\",\n                        \"operationId\": \"create_team_teams__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/TeamCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/teams/{team_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Team\",\n                        \"operationId\": \"read_team_teams__team_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublicWithHeroes\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Team\",\n                        \"operationId\": \"delete_team_teams__team_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Team\",\n                        \"operationId\": \"update_team_teams__team_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/TeamUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroPublicWithTeam\": {\n                        \"title\": \"HeroPublicWithTeam\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                            \"team\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/TeamPublic\"},\n                                    {\"type\": \"null\"},\n                                ]\n                            },\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"secret_name\": {\n                                \"title\": \"Secret Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"TeamCreate\": {\n                        \"title\": \"TeamCreate\",\n                        \"required\": [\"name\", \"headquarters\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"headquarters\": {\"title\": \"Headquarters\", \"type\": \"string\"},\n                        },\n                    },\n                    \"TeamPublic\": {\n                        \"title\": \"TeamPublic\",\n                        \"required\": [\"name\", \"headquarters\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"headquarters\": {\"title\": \"Headquarters\", \"type\": \"string\"},\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"TeamPublicWithHeroes\": {\n                        \"title\": \"TeamPublicWithHeroes\",\n                        \"required\": [\"name\", \"headquarters\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"headquarters\": {\"title\": \"Headquarters\", \"type\": \"string\"},\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                            \"heroes\": {\n                                \"title\": \"Heroes\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/HeroPublic\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"TeamUpdate\": {\n                        \"title\": \"TeamUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\n                                \"title\": \"Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"headquarters\": {\n                                \"title\": \"Headquarters\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_response_model/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.response_model.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        response = client.post(\"/heroes/\", json=hero_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero_data[\"name\"]\n        assert data[\"secret_name\"] == hero_data[\"secret_name\"]\n        assert data[\"id\"] is not None\n        assert data[\"age\"] is None\n\n        response = client.get(\"/heroes/\")\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert len(data) == 1\n        assert data[0][\"name\"] == hero_data[\"name\"]\n        assert data[0][\"secret_name\"] == hero_data[\"secret_name\"]\n\n        response = client.get(\"/openapi.json\")\n\n        assert response.status_code == 200, response.text\n\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Hero\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Hero\": {\n                        \"title\": \"Hero\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\n                                \"title\": \"Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_session_with_dependency/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.session_with_dependency.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        response = client.get(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        assert response.status_code == 200, response.text\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n\n        response = client.delete(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n\n        response = client.delete(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"secret_name\": {\n                                \"title\": \"Secret Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_simple_hero_api/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.fastapi.simple_hero_api.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero1_data[\"name\"]\n        assert data[\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[\"id\"] is not None\n        assert data[\"age\"] is None\n\n        response = client.post(\"/heroes/\", json=hero2_data)\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero2_data[\"name\"]\n        assert data[\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[\"id\"] == hero2_data[\"id\"], (\n            \"Up to this point it's still possible to \"\n            \"set the ID of the hero in the request\"\n        )\n        assert data[\"age\"] is None\n\n        response = client.get(\"/heroes/\")\n        data = response.json()\n\n        assert response.status_code == 200, response.text\n        assert len(data) == 2\n        assert data[0][\"name\"] == hero1_data[\"name\"]\n        assert data[0][\"secret_name\"] == hero1_data[\"secret_name\"]\n        assert data[1][\"name\"] == hero2_data[\"name\"]\n        assert data[1][\"secret_name\"] == hero2_data[\"secret_name\"]\n        assert data[1][\"id\"] == hero2_data[\"id\"]\n\n        response = client.get(\"/openapi.json\")\n\n        assert response.status_code == 200, response.text\n\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Hero\": {\n                        \"title\": \"Hero\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\n                                \"title\": \"Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_teams/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.fastapi.teams.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        response = client.get(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        assert response.status_code == 200, response.text\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n        response = client.delete(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 2\n        response = client.delete(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n\n        team_preventers = {\"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}\n        team_z_force = {\"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"}\n        response = client.post(\"/teams/\", json=team_preventers)\n        assert response.status_code == 200, response.text\n        team_preventers_data = response.json()\n        team_preventers_id = team_preventers_data[\"id\"]\n        response = client.post(\"/teams/\", json=team_z_force)\n        assert response.status_code == 200, response.text\n        team_z_force_data = response.json()\n        team_z_force_data[\"id\"]\n        response = client.get(\"/teams/\")\n        data = response.json()\n        assert len(data) == 2\n        response = client.get(f\"/teams/{team_preventers_id}\")\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data == team_preventers_data\n        response = client.get(\"/teams/9000\")\n        assert response.status_code == 404, response.text\n        response = client.patch(\n            f\"/teams/{team_preventers_id}\", json={\"headquarters\": \"Preventers Tower\"}\n        )\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == team_preventers[\"name\"]\n        assert data[\"headquarters\"] == \"Preventers Tower\"\n        response = client.patch(\"/teams/9000\", json={\"name\": \"Freedom League\"})\n        assert response.status_code == 404, response.text\n        response = client.delete(f\"/teams/{team_preventers_id}\")\n        assert response.status_code == 200, response.text\n        response = client.delete(\"/teams/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/teams/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 1\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/teams/\": {\n                    \"get\": {\n                        \"summary\": \"Read Teams\",\n                        \"operationId\": \"read_teams_teams__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Teams Teams  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/TeamPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Team\",\n                        \"operationId\": \"create_team_teams__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/TeamCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/teams/{team_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Team\",\n                        \"operationId\": \"read_team_teams__team_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Team\",\n                        \"operationId\": \"delete_team_teams__team_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Team\",\n                        \"operationId\": \"update_team_teams__team_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Team Id\", \"type\": \"integer\"},\n                                \"name\": \"team_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/TeamUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/TeamPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"secret_name\": {\n                                \"title\": \"Secret Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"team_id\": {\n                                \"title\": \"Team Id\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"TeamCreate\": {\n                        \"title\": \"TeamCreate\",\n                        \"required\": [\"name\", \"headquarters\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"headquarters\": {\"title\": \"Headquarters\", \"type\": \"string\"},\n                        },\n                    },\n                    \"TeamPublic\": {\n                        \"title\": \"TeamPublic\",\n                        \"required\": [\"name\", \"headquarters\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"headquarters\": {\"title\": \"Headquarters\", \"type\": \"string\"},\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"TeamUpdate\": {\n                        \"title\": \"TeamUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"headquarters\": {\n                                \"title\": \"Headquarters\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_update/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.fastapi.update.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\"}\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        hero3 = response.json()\n        hero3_id = hero3[\"id\"]\n        response = client.get(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero2_data[\"name\"], \"The name should not be set to none\"\n        assert data[\"secret_name\"] == \"Spider-Youngster\", (\n            \"The secret name should be updated\"\n        )\n\n        response = client.patch(f\"/heroes/{hero3_id}\", json={\"age\": None})\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero3_data[\"name\"]\n        assert data[\"age\"] is None, (\n            \"A field should be updatable to None, even if that's the default\"\n        )\n\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100.0,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"secret_name\": {\n                                \"title\": \"Secret Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_fastapi/test_update/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\nfrom sqlmodel import Session, create_engine\nfrom sqlmodel.pool import StaticPool\n\nfrom tests.conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.fastapi.update.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool\n    )\n    return mod\n\n\ndef test_tutorial(module: ModuleType):\n    with TestClient(module.app) as client:\n        hero1_data = {\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"password\": \"chimichanga\",\n        }\n        hero2_data = {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"id\": 9000,\n            \"password\": \"auntmay\",\n        }\n        hero3_data = {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n            \"password\": \"bestpreventer\",\n        }\n        response = client.post(\"/heroes/\", json=hero1_data)\n        assert response.status_code == 200, response.text\n        hero1 = response.json()\n        assert \"password\" not in hero1\n        assert \"hashed_password\" not in hero1\n        hero1_id = hero1[\"id\"]\n        response = client.post(\"/heroes/\", json=hero2_data)\n        assert response.status_code == 200, response.text\n        hero2 = response.json()\n        hero2_id = hero2[\"id\"]\n        response = client.post(\"/heroes/\", json=hero3_data)\n        assert response.status_code == 200, response.text\n        hero3 = response.json()\n        hero3_id = hero3[\"id\"]\n        response = client.get(f\"/heroes/{hero2_id}\")\n        assert response.status_code == 200, response.text\n        fetched_hero2 = response.json()\n        assert \"password\" not in fetched_hero2\n        assert \"hashed_password\" not in fetched_hero2\n        response = client.get(\"/heroes/9000\")\n        assert response.status_code == 404, response.text\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        data = response.json()\n        assert len(data) == 3\n        for response_hero in data:\n            assert \"password\" not in response_hero\n            assert \"hashed_password\" not in response_hero\n\n        # Test hashed passwords\n        with Session(module.engine) as session:\n            hero1_db = session.get(module.Hero, hero1_id)\n            assert hero1_db\n            assert not hasattr(hero1_db, \"password\")\n            assert hero1_db.hashed_password == \"not really hashed chimichanga hehehe\"\n            hero2_db = session.get(module.Hero, hero2_id)\n            assert hero2_db\n            assert not hasattr(hero2_db, \"password\")\n            assert hero2_db.hashed_password == \"not really hashed auntmay hehehe\"\n            hero3_db = session.get(module.Hero, hero3_id)\n            assert hero3_db\n            assert not hasattr(hero3_db, \"password\")\n            assert hero3_db.hashed_password == \"not really hashed bestpreventer hehehe\"\n\n        response = client.patch(\n            f\"/heroes/{hero2_id}\", json={\"secret_name\": \"Spider-Youngster\"}\n        )\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero2_data[\"name\"], \"The name should not be set to none\"\n        assert data[\"secret_name\"] == \"Spider-Youngster\", (\n            \"The secret name should be updated\"\n        )\n        assert \"password\" not in data\n        assert \"hashed_password\" not in data\n        with Session(module.engine) as session:\n            hero2b_db = session.get(module.Hero, hero2_id)\n            assert hero2b_db\n            assert not hasattr(hero2b_db, \"password\")\n            assert hero2b_db.hashed_password == \"not really hashed auntmay hehehe\"\n\n        response = client.patch(f\"/heroes/{hero3_id}\", json={\"age\": None})\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero3_data[\"name\"]\n        assert data[\"age\"] is None, (\n            \"A field should be updatable to None, even if that's the default\"\n        )\n        assert \"password\" not in data\n        assert \"hashed_password\" not in data\n        with Session(module.engine) as session:\n            hero3b_db = session.get(module.Hero, hero3_id)\n            assert hero3b_db\n            assert not hasattr(hero3b_db, \"password\")\n            assert hero3b_db.hashed_password == \"not really hashed bestpreventer hehehe\"\n\n        # Test update dict, hashed_password\n        response = client.patch(\n            f\"/heroes/{hero3_id}\", json={\"password\": \"philantroplayboy\"}\n        )\n        data = response.json()\n        assert response.status_code == 200, response.text\n        assert data[\"name\"] == hero3_data[\"name\"]\n        assert data[\"age\"] is None\n        assert \"password\" not in data\n        assert \"hashed_password\" not in data\n        with Session(module.engine) as session:\n            hero3b_db = session.get(module.Hero, hero3_id)\n            assert hero3b_db\n            assert not hasattr(hero3b_db, \"password\")\n            assert (\n                hero3b_db.hashed_password == \"not really hashed philantroplayboy hehehe\"\n            )\n\n        response = client.patch(\"/heroes/9001\", json={\"name\": \"Dragon Cube X\"})\n        assert response.status_code == 404, response.text\n\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Offset\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"maximum\": 100,\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Hero Id\", \"type\": \"integer\"},\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"HeroCreate\": {\n                        \"title\": \"HeroCreate\",\n                        \"required\": [\"name\", \"secret_name\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"password\": {\"type\": \"string\", \"title\": \"Password\"},\n                        },\n                    },\n                    \"HeroPublic\": {\n                        \"title\": \"HeroPublic\",\n                        \"required\": [\"name\", \"secret_name\", \"id\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"secret_name\": {\"title\": \"Secret Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"id\": {\"title\": \"Id\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"HeroUpdate\": {\n                        \"title\": \"HeroUpdate\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Name\",\n                            },\n                            \"secret_name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Secret Name\",\n                            },\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"password\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Password\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": IsOneOf(\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                            {\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                            },\n                        ),\n                    },\n                }\n            },\n        }\n"
  },
  {
    "path": "tests/test_tutorial/test_indexes/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_indexes/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.indexes.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"secret_name\": \"Dive Wilson\", \"age\": None, \"id\": 1, \"name\": \"Deadpond\"}]\n    ]\n\n    insp: Inspector = inspect(mod.engine)\n    indexes = insp.get_indexes(str(mod.Hero.__tablename__))\n    expected_indexes = [\n        {\n            \"name\": \"ix_hero_name\",\n            \"dialect_options\": {},\n            \"column_names\": [\"name\"],\n            \"unique\": 0,\n        },\n        {\n            \"name\": \"ix_hero_age\",\n            \"dialect_options\": {},\n            \"column_names\": [\"age\"],\n            \"unique\": 0,\n        },\n    ]\n    for index in expected_indexes:\n        assert index in indexes, \"This expected index should be in the indexes in DB\"\n        # Now that this index was checked, remove it from the list of indexes\n        indexes.pop(indexes.index(index))\n    assert len(indexes) == 0, \"The database should only have the expected indexes\"\n"
  },
  {
    "path": "tests/test_tutorial/test_indexes/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.indexes.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"name\": \"Tarantula\", \"secret_name\": \"Natalia Roman-on\", \"age\": 32, \"id\": 4}],\n        [{\"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35, \"id\": 5}],\n    ]\n\n    insp: Inspector = inspect(mod.engine)\n    indexes = insp.get_indexes(str(mod.Hero.__tablename__))\n    expected_indexes = [\n        {\n            \"name\": \"ix_hero_name\",\n            \"dialect_options\": {},\n            \"column_names\": [\"name\"],\n            \"unique\": 0,\n        },\n        {\n            \"name\": \"ix_hero_age\",\n            \"dialect_options\": {},\n            \"column_names\": [\"age\"],\n            \"unique\": 0,\n        },\n    ]\n    for index in expected_indexes:\n        assert index in indexes, \"This expected index should be in the indexes in DB\"\n        # Now that this index was checked, remove it from the list of indexes\n        indexes.pop(indexes.index(index))\n    assert len(indexes) == 0, \"The database should only have the expected indexes\"\n"
  },
  {
    "path": "tests/test_tutorial/test_insert/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_insert/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import Session, create_engine, select\n\nfrom ...conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.insert.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(mod: ModuleType):\n    mod.main()\n    with Session(mod.engine) as session:\n        heroes = session.exec(select(mod.Hero)).all()\n    heroes_by_name = {hero.name: hero for hero in heroes}\n    deadpond = heroes_by_name[\"Deadpond\"]\n    spider_boy = heroes_by_name[\"Spider-Boy\"]\n    rusty_man = heroes_by_name[\"Rusty-Man\"]\n    assert deadpond.name == \"Deadpond\"\n    assert deadpond.age is None\n    assert deadpond.id is not None\n    assert deadpond.secret_name == \"Dive Wilson\"\n    assert spider_boy.name == \"Spider-Boy\"\n    assert spider_boy.age is None\n    assert spider_boy.id is not None\n    assert spider_boy.secret_name == \"Pedro Parqueador\"\n    assert rusty_man.name == \"Rusty-Man\"\n    assert rusty_man.age == 48\n    assert rusty_man.id is not None\n    assert rusty_man.secret_name == \"Tommy Sharp\"\n"
  },
  {
    "path": "tests/test_tutorial/test_insert/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import Session, create_engine, select\n\nfrom ...conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.insert.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(mod: ModuleType):\n    mod.main()\n    with Session(mod.engine) as session:\n        heroes = session.exec(select(mod.Hero)).all()\n    heroes_by_name = {hero.name: hero for hero in heroes}\n    deadpond = heroes_by_name[\"Deadpond\"]\n    spider_boy = heroes_by_name[\"Spider-Boy\"]\n    rusty_man = heroes_by_name[\"Rusty-Man\"]\n    assert deadpond.name == \"Deadpond\"\n    assert deadpond.age is None\n    assert deadpond.id is not None\n    assert deadpond.secret_name == \"Dive Wilson\"\n    assert spider_boy.name == \"Spider-Boy\"\n    assert spider_boy.age is None\n    assert spider_boy.id is not None\n    assert spider_boy.secret_name == \"Pedro Parqueador\"\n    assert rusty_man.name == \"Rusty-Man\"\n    assert rusty_man.age == 48\n    assert rusty_man.id is not None\n    assert rusty_man.secret_name == \"Tommy Sharp\"\n"
  },
  {
    "path": "tests/test_tutorial/test_insert/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import Session, create_engine, select\n\nfrom ...conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.insert.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(mod: ModuleType):\n    mod.main()\n    with Session(mod.engine) as session:\n        heroes = session.exec(select(mod.Hero)).all()\n    heroes_by_name = {hero.name: hero for hero in heroes}\n    deadpond = heroes_by_name[\"Deadpond\"]\n    spider_boy = heroes_by_name[\"Spider-Boy\"]\n    rusty_man = heroes_by_name[\"Rusty-Man\"]\n    assert deadpond.name == \"Deadpond\"\n    assert deadpond.age is None\n    assert deadpond.id is not None\n    assert deadpond.secret_name == \"Dive Wilson\"\n    assert spider_boy.name == \"Spider-Boy\"\n    assert spider_boy.age is None\n    assert spider_boy.id is not None\n    assert spider_boy.secret_name == \"Pedro Parqueador\"\n    assert rusty_man.name == \"Rusty-Man\"\n    assert rusty_man.age == 48\n    assert rusty_man.id is not None\n    assert rusty_man.secret_name == \"Tommy Sharp\"\n"
  },
  {
    "path": "tests/test_tutorial/test_limit_and_offset/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_limit_and_offset/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.offset_and_limit.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        [\n            {\"id\": 1, \"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"age\": None},\n            {\n                \"id\": 2,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n            },\n            {\"id\": 3, \"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48},\n        ]\n    ]\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_limit_and_offset/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.offset_and_limit.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        [\n            {\n                \"id\": 4,\n                \"name\": \"Tarantula\",\n                \"secret_name\": \"Natalia Roman-on\",\n                \"age\": 32,\n            },\n            {\"id\": 5, \"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35},\n            {\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36},\n        ]\n    ]\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_limit_and_offset/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.offset_and_limit.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        [\n            {\n                \"id\": 7,\n                \"name\": \"Captain North America\",\n                \"secret_name\": \"Esteban Rogelios\",\n                \"age\": 93,\n            }\n        ]\n    ]\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_limit_and_offset/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.offset_and_limit.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            [\n                {\"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36, \"id\": 6},\n                {\"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48, \"id\": 3},\n            ]\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_many_to_many/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_many_to_many/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.many_to_many.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Deadpond:\",\n        {\"id\": 1, \"secret_name\": \"Dive Wilson\", \"age\": None, \"name\": \"Deadpond\"},\n    ],\n    [\n        \"Deadpond teams:\",\n        [\n            {\"id\": 1, \"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"},\n            {\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n        ],\n    ],\n    [\n        \"Rusty-Man:\",\n        {\"id\": 2, \"secret_name\": \"Tommy Sharp\", \"age\": 48, \"name\": \"Rusty-Man\"},\n    ],\n    [\n        \"Rusty-Man Teams:\",\n        [{\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}],\n    ],\n    [\n        \"Spider-Boy:\",\n        {\"id\": 3, \"secret_name\": \"Pedro Parqueador\", \"age\": None, \"name\": \"Spider-Boy\"},\n    ],\n    [\n        \"Spider-Boy Teams:\",\n        [{\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}],\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_many_to_many/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.many_to_many.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Deadpond:\",\n        {\"id\": 1, \"secret_name\": \"Dive Wilson\", \"age\": None, \"name\": \"Deadpond\"},\n    ],\n    [\n        \"Deadpond teams:\",\n        [\n            {\"id\": 1, \"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"},\n            {\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n        ],\n    ],\n    [\n        \"Rusty-Man:\",\n        {\"id\": 2, \"secret_name\": \"Tommy Sharp\", \"age\": 48, \"name\": \"Rusty-Man\"},\n    ],\n    [\n        \"Rusty-Man Teams:\",\n        [{\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}],\n    ],\n    [\n        \"Spider-Boy:\",\n        {\"id\": 3, \"secret_name\": \"Pedro Parqueador\", \"age\": None, \"name\": \"Spider-Boy\"},\n    ],\n    [\n        \"Spider-Boy Teams:\",\n        [{\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}],\n    ],\n    [\n        \"Updated Spider-Boy's Teams:\",\n        [\n            {\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n            {\"id\": 1, \"name\": \"Z-Force\", \"headquarters\": \"Sister Margaret's Bar\"},\n        ],\n    ],\n    [\n        \"Z-Force heroes:\",\n        [\n            {\"id\": 1, \"secret_name\": \"Dive Wilson\", \"age\": None, \"name\": \"Deadpond\"},\n            {\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"name\": \"Spider-Boy\",\n            },\n        ],\n    ],\n    [\n        \"Reverted Z-Force's heroes:\",\n        [{\"id\": 1, \"secret_name\": \"Dive Wilson\", \"age\": None, \"name\": \"Deadpond\"}],\n    ],\n    [\n        \"Reverted Spider-Boy's teams:\",\n        [{\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"}],\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_many_to_many/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.many_to_many.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Z-Force hero:\",\n        {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"id\": 1, \"age\": None},\n        \"is training:\",\n        False,\n    ],\n    [\n        \"Preventers hero:\",\n        {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"id\": 1, \"age\": None},\n        \"is training:\",\n        True,\n    ],\n    [\n        \"Preventers hero:\",\n        {\"name\": \"Spider-Boy\", \"secret_name\": \"Pedro Parqueador\", \"id\": 2, \"age\": None},\n        \"is training:\",\n        True,\n    ],\n    [\n        \"Preventers hero:\",\n        {\"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"id\": 3, \"age\": 48},\n        \"is training:\",\n        False,\n    ],\n    [\n        \"Updated Spider-Boy's Teams:\",\n        [\n            {\"team_id\": 2, \"is_training\": True, \"hero_id\": 2},\n            {\"team_id\": 1, \"is_training\": True, \"hero_id\": 2},\n        ],\n    ],\n    [\n        \"Z-Force heroes:\",\n        [\n            {\"team_id\": 1, \"is_training\": False, \"hero_id\": 1},\n            {\"team_id\": 1, \"is_training\": True, \"hero_id\": 2},\n        ],\n    ],\n    [\n        \"Spider-Boy team:\",\n        {\"headquarters\": \"Sharp Tower\", \"id\": 2, \"name\": \"Preventers\"},\n        \"is training:\",\n        False,\n    ],\n    [\n        \"Spider-Boy team:\",\n        {\"headquarters\": \"Sister Margaret's Bar\", \"id\": 1, \"name\": \"Z-Force\"},\n        \"is training:\",\n        True,\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_one/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\n                \"name\": \"Tarantula\",\n                \"secret_name\": \"Natalia Roman-on\",\n                \"age\": 32,\n                \"id\": 4,\n            },\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [[\"Hero:\", None]]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"age\": None, \"id\": 1},\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy.exc import MultipleResultsFound\nfrom sqlmodel import Session, create_engine, delete\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    with pytest.raises(MultipleResultsFound):\n        mod.main()\n    with Session(mod.engine) as session:\n        # TODO: create delete() function\n        # TODO: add overloads for .exec() with delete object\n        session.exec(delete(mod.Hero))\n        session.add(mod.Hero(name=\"Test Hero\", secret_name=\"Secret Test Hero\", age=24))\n        session.commit()\n\n    mod.select_heroes()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\n                \"id\": 1,\n                \"name\": \"Test Hero\",\n                \"secret_name\": \"Secret Test Hero\",\n                \"age\": 24,\n            },\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial005.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy.exc import NoResultFound\nfrom sqlmodel import Session, create_engine, delete\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    with pytest.raises(NoResultFound):\n        mod.main()\n    with Session(mod.engine) as session:\n        # TODO: create delete() function\n        # TODO: add overloads for .exec() with delete object\n        session.exec(delete(mod.Hero))\n        session.add(mod.Hero(name=\"Test Hero\", secret_name=\"Secret Test Hero\", age=24))\n        session.commit()\n\n    mod.select_heroes()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\n                \"id\": 1,\n                \"name\": \"Test Hero\",\n                \"secret_name\": \"Secret Test Hero\",\n                \"age\": 24,\n            },\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial006.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial006_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"age\": None, \"id\": 1},\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial007.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial007_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"age\": None, \"id\": 1},\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial008.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial008_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Hero:\",\n            {\"name\": \"Deadpond\", \"secret_name\": \"Dive Wilson\", \"age\": None, \"id\": 1},\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_one/test_tutorial009.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial009_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.one.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [[\"Hero:\", None]]\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_back_populates/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy.exc import SAWarning\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.back_populates.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 2,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Team Wakaland:\",\n        {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 32,\n            \"id\": 6,\n            \"secret_name\": \"Natalia Roman-on\",\n            \"team_id\": 2,\n            \"name\": \"Tarantula\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 36,\n            \"id\": 7,\n            \"secret_name\": \"Steve Weird\",\n            \"team_id\": 2,\n            \"name\": \"Dr. Weird\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 93,\n            \"id\": 8,\n            \"secret_name\": \"Esteban Rogelios\",\n            \"team_id\": 2,\n            \"name\": \"Captain North America\",\n        },\n    ],\n    [\n        \"Preventers heroes:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\n        \"Hero Spider-Boy:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team:\",\n        {\"headquarters\": \"Sharp Tower\", \"id\": 2, \"name\": \"Preventers\"},\n    ],\n    [\n        \"Preventers Team Heroes:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\n        \"Spider-Boy without team:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team Heroes again:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\"After committing\"],\n    [\n        \"Spider-Boy after commit:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team Heroes after commit:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    with pytest.warns(SAWarning):\n        mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.back_populates.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 2,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Team Wakaland:\",\n        {\"id\": 3, \"name\": \"Wakaland\", \"headquarters\": \"Wakaland Capital City\"},\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 32,\n            \"id\": 6,\n            \"secret_name\": \"Natalia Roman-on\",\n            \"team_id\": 2,\n            \"name\": \"Tarantula\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 36,\n            \"id\": 7,\n            \"secret_name\": \"Steve Weird\",\n            \"team_id\": 2,\n            \"name\": \"Dr. Weird\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 93,\n            \"id\": 8,\n            \"secret_name\": \"Esteban Rogelios\",\n            \"team_id\": 2,\n            \"name\": \"Captain North America\",\n        },\n    ],\n    [\n        \"Preventers heroes:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\n        \"Hero Spider-Boy:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team:\",\n        {\"id\": 2, \"name\": \"Preventers\", \"headquarters\": \"Sharp Tower\"},\n    ],\n    [\n        \"Preventers Team Heroes:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\n        \"Spider-Boy without team:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team Heroes again:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\"After committing\"],\n    [\n        \"Spider-Boy after commit:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Preventers Team Heroes after commit:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_back_populates/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy import inspect\nfrom sqlalchemy.engine.reflection import Inspector\nfrom sqlmodel import create_engine\n\nfrom ....conftest import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.back_populates.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(mod: ModuleType):\n    mod.main()\n    insp: Inspector = inspect(mod.engine)\n    assert insp.has_table(str(mod.Hero.__tablename__))\n    assert insp.has_table(str(mod.Weapon.__tablename__))\n    assert insp.has_table(str(mod.Power.__tablename__))\n    assert insp.has_table(str(mod.Team.__tablename__))\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_create_and_update_relationships/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.create_and_update_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 2,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Team Wakaland:\",\n        {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 32,\n            \"id\": 6,\n            \"secret_name\": \"Natalia Roman-on\",\n            \"team_id\": 2,\n            \"name\": \"Tarantula\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 36,\n            \"id\": 7,\n            \"secret_name\": \"Steve Weird\",\n            \"team_id\": 2,\n            \"name\": \"Dr. Weird\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 93,\n            \"id\": 8,\n            \"secret_name\": \"Esteban Rogelios\",\n            \"team_id\": 2,\n            \"name\": \"Captain North America\",\n        },\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_define_relationship_attributes/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.define_relationship_attributes.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"name\": \"Deadpond\",\n            \"age\": None,\n            \"team_id\": 1,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"name\": \"Rusty-Man\",\n            \"age\": 48,\n            \"team_id\": 2,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"name\": \"Spider-Boy\",\n            \"age\": None,\n            \"team_id\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n        },\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.cascade_delete_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"team_id\": 1,\n                \"id\": 1,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"id\": 2,\n                \"age\": 48,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": None,\n                \"id\": 3,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Updated hero:\",\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"id\": 3,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Team Wakaland:\",\n            {\"name\": \"Wakaland\", \"id\": 3, \"headquarters\": \"Wakaland Capital City\"},\n        ],\n        [\n            \"Deleted team:\",\n            {\"name\": \"Wakaland\", \"id\": 3, \"headquarters\": \"Wakaland Capital City\"},\n        ],\n        [\"Black Lion not found:\", None],\n        [\"Princess Sure-E not found:\", None],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.cascade_delete_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 1,\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"team_id\": 1,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": None,\n            },\n        ],\n        [\n            \"Updated hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Team Wakaland:\",\n            {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Deleted team:\",\n            {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Black Lion has no team:\",\n            {\n                \"age\": 35,\n                \"id\": 4,\n                \"name\": \"Black Lion\",\n                \"secret_name\": \"Trevor Challa\",\n                \"team_id\": None,\n            },\n        ],\n        [\n            \"Princess Sure-E has no team:\",\n            {\n                \"age\": None,\n                \"id\": 5,\n                \"name\": \"Princess Sure-E\",\n                \"secret_name\": \"Sure-E\",\n                \"team_id\": None,\n            },\n        ],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.cascade_delete_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 1,\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"team_id\": 1,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": None,\n            },\n        ],\n        [\n            \"Updated hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Team Wakaland:\",\n            {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Deleted team:\",\n            {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Black Lion has no team:\",\n            {\n                \"age\": 35,\n                \"id\": 4,\n                \"name\": \"Black Lion\",\n                \"secret_name\": \"Trevor Challa\",\n                \"team_id\": None,\n            },\n        ],\n        [\n            \"Princess Sure-E has no team:\",\n            {\n                \"age\": None,\n                \"id\": 5,\n                \"name\": \"Princess Sure-E\",\n                \"secret_name\": \"Sure-E\",\n                \"team_id\": None,\n            },\n        ],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlalchemy.exc import IntegrityError\nfrom sqlmodel import Session, create_engine, select\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.cascade_delete_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.create_db_and_tables()\n    mod.create_heroes()\n    mod.select_deleted_heroes()\n    with Session(mod.engine) as session:\n        team = session.exec(select(mod.Team).where(mod.Team.name == \"Wakaland\")).one()\n        team.heroes.clear()\n        session.add(team)\n        session.commit()\n    mod.delete_team()\n    assert print_mock.calls == [\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 1,\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"team_id\": 1,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": None,\n            },\n        ],\n        [\n            \"Updated hero:\",\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n            },\n        ],\n        [\n            \"Team Wakaland:\",\n            {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Black Lion has no team:\",\n            {\n                \"age\": 35,\n                \"id\": 4,\n                \"name\": \"Black Lion\",\n                \"secret_name\": \"Trevor Challa\",\n                \"team_id\": 3,\n            },\n        ],\n        [\n            \"Princess Sure-E has no team:\",\n            {\n                \"age\": None,\n                \"id\": 5,\n                \"name\": \"Princess Sure-E\",\n                \"secret_name\": \"Sure-E\",\n                \"team_id\": 3,\n            },\n        ],\n        [\n            \"Deleted team:\",\n            {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n        ],\n    ]\n\n    with pytest.raises(IntegrityError) as exc:\n        mod.main()\n    assert \"FOREIGN KEY constraint failed\" in str(exc.value)\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_delete_records_relationship/test_tutorial005.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.cascade_delete_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"team_id\": 1,\n                \"id\": 1,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Rusty-Man\",\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"id\": 2,\n                \"age\": 48,\n            },\n        ],\n        [\n            \"Created hero:\",\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": None,\n                \"id\": 3,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Updated hero:\",\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"id\": 3,\n                \"age\": None,\n            },\n        ],\n        [\n            \"Team Wakaland:\",\n            {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Team with removed heroes:\",\n            {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Deleted team:\",\n            {\"id\": 3, \"headquarters\": \"Wakaland Capital City\", \"name\": \"Wakaland\"},\n        ],\n        [\n            \"Black Lion has no team:\",\n            {\n                \"name\": \"Black Lion\",\n                \"secret_name\": \"Trevor Challa\",\n                \"team_id\": None,\n                \"id\": 4,\n                \"age\": 35,\n            },\n        ],\n        [\n            \"Princess Sure-E has no team:\",\n            {\n                \"name\": \"Princess Sure-E\",\n                \"secret_name\": \"Sure-E\",\n                \"team_id\": None,\n                \"id\": 5,\n                \"age\": None,\n            },\n        ],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_read_relationships/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.read_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 2,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Team Wakaland:\",\n        {\"headquarters\": \"Wakaland Capital City\", \"id\": 3, \"name\": \"Wakaland\"},\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 32,\n            \"id\": 6,\n            \"secret_name\": \"Natalia Roman-on\",\n            \"team_id\": 2,\n            \"name\": \"Tarantula\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 36,\n            \"id\": 7,\n            \"secret_name\": \"Steve Weird\",\n            \"team_id\": 2,\n            \"name\": \"Dr. Weird\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 93,\n            \"id\": 8,\n            \"secret_name\": \"Esteban Rogelios\",\n            \"team_id\": 2,\n            \"name\": \"Captain North America\",\n        },\n    ],\n    [\n        \"Spider-Boy's team:\",\n        {\"headquarters\": \"Sharp Tower\", \"id\": 2, \"name\": \"Preventers\"},\n    ],\n    [\n        \"Spider-Boy's team again:\",\n        {\"headquarters\": \"Sharp Tower\", \"id\": 2, \"name\": \"Preventers\"},\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_relationship_attributes/test_read_relationships/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ....conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(\n        f\"docs_src.tutorial.relationship_attributes.read_relationships.{request.param}\"\n    )\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\nexpected_calls = [\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 1,\n            \"secret_name\": \"Dive Wilson\",\n            \"team_id\": 1,\n            \"name\": \"Deadpond\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": 48,\n            \"id\": 2,\n            \"secret_name\": \"Tommy Sharp\",\n            \"team_id\": 2,\n            \"name\": \"Rusty-Man\",\n        },\n    ],\n    [\n        \"Created hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": 2,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n    [\n        \"Team Wakaland:\",\n        {\"id\": 3, \"name\": \"Wakaland\", \"headquarters\": \"Wakaland Capital City\"},\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 32,\n            \"id\": 6,\n            \"secret_name\": \"Natalia Roman-on\",\n            \"team_id\": 2,\n            \"name\": \"Tarantula\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 36,\n            \"id\": 7,\n            \"secret_name\": \"Steve Weird\",\n            \"team_id\": 2,\n            \"name\": \"Dr. Weird\",\n        },\n    ],\n    [\n        \"Preventers new hero:\",\n        {\n            \"age\": 93,\n            \"id\": 8,\n            \"secret_name\": \"Esteban Rogelios\",\n            \"team_id\": 2,\n            \"name\": \"Captain North America\",\n        },\n    ],\n    [\n        \"Preventers heroes:\",\n        [\n            {\n                \"age\": 48,\n                \"id\": 2,\n                \"secret_name\": \"Tommy Sharp\",\n                \"team_id\": 2,\n                \"name\": \"Rusty-Man\",\n            },\n            {\n                \"age\": None,\n                \"id\": 3,\n                \"secret_name\": \"Pedro Parqueador\",\n                \"team_id\": 2,\n                \"name\": \"Spider-Boy\",\n            },\n            {\n                \"age\": 32,\n                \"id\": 6,\n                \"secret_name\": \"Natalia Roman-on\",\n                \"team_id\": 2,\n                \"name\": \"Tarantula\",\n            },\n            {\n                \"age\": 36,\n                \"id\": 7,\n                \"secret_name\": \"Steve Weird\",\n                \"team_id\": 2,\n                \"name\": \"Dr. Weird\",\n            },\n            {\n                \"age\": 93,\n                \"id\": 8,\n                \"secret_name\": \"Esteban Rogelios\",\n                \"team_id\": 2,\n                \"name\": \"Captain North America\",\n            },\n        ],\n    ],\n    [\n        \"Spider-Boy without team:\",\n        {\n            \"age\": None,\n            \"id\": 3,\n            \"secret_name\": \"Pedro Parqueador\",\n            \"team_id\": None,\n            \"name\": \"Spider-Boy\",\n        },\n    ],\n]\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_select/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_select/test_tutorial001_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom typing import Any\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\ndef check_calls(calls: list[list[str | dict[str, Any]]]):\n    assert calls[0][0] == {\n        \"name\": \"Deadpond\",\n        \"secret_name\": \"Dive Wilson\",\n        \"age\": None,\n        \"id\": 1,\n    }\n    assert calls[1][0] == {\n        \"name\": \"Spider-Boy\",\n        \"secret_name\": \"Pedro Parqueador\",\n        \"age\": None,\n        \"id\": 2,\n    }\n    assert calls[2][0] == {\n        \"name\": \"Rusty-Man\",\n        \"secret_name\": \"Tommy Sharp\",\n        \"age\": 48,\n        \"id\": 3,\n    }\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(f\"docs_src.tutorial.select.{request.param}\")\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial_001(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    check_calls(print_mock.calls)\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial_002(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    check_calls(print_mock.calls)\n"
  },
  {
    "path": "tests/test_tutorial/test_select/test_tutorial003_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom typing import Any\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\ndef check_calls(calls: list[list[str | dict[str, Any]]]):\n    assert calls[0][0] == [\n        {\n            \"name\": \"Deadpond\",\n            \"secret_name\": \"Dive Wilson\",\n            \"age\": None,\n            \"id\": 1,\n        },\n        {\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n            \"id\": 2,\n        },\n        {\n            \"name\": \"Rusty-Man\",\n            \"secret_name\": \"Tommy Sharp\",\n            \"age\": 48,\n            \"id\": 3,\n        },\n    ]\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(f\"docs_src.tutorial.select.{request.param}\")\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial_003(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    check_calls(print_mock.calls)\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial_004(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    check_calls(print_mock.calls)\n"
  },
  {
    "path": "tests/test_tutorial/test_update/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_update/test_tutorial001_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Hero:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": None,\n        },\n    ],\n    [\n        \"Updated hero:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Boy\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": 16,\n        },\n    ],\n]\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(f\"docs_src.tutorial.update.{request.param}\")\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial001(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial002(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_update/test_tutorial003_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\nexpected_calls = [\n    [\n        \"Hero 1:\",\n        {\"id\": 2, \"name\": \"Spider-Boy\", \"secret_name\": \"Pedro Parqueador\", \"age\": None},\n    ],\n    [\n        \"Hero 2:\",\n        {\n            \"id\": 7,\n            \"name\": \"Captain North America\",\n            \"secret_name\": \"Esteban Rogelios\",\n            \"age\": 93,\n        },\n    ],\n    [\n        \"Updated hero 1:\",\n        {\n            \"id\": 2,\n            \"name\": \"Spider-Youngster\",\n            \"secret_name\": \"Pedro Parqueador\",\n            \"age\": 16,\n        },\n    ],\n    [\n        \"Updated hero 2:\",\n        {\n            \"id\": 7,\n            \"name\": \"Captain North America Except Canada\",\n            \"secret_name\": \"Esteban Rogelios\",\n            \"age\": 110,\n        },\n    ],\n]\n\n\n@pytest.fixture(name=\"module\")\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    module = importlib.import_module(f\"docs_src.tutorial.update.{request.param}\")\n    module.sqlite_url = \"sqlite://\"\n    module.engine = create_engine(module.sqlite_url)\n    return module\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial003(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n\n\n@pytest.mark.parametrize(\n    \"module\",\n    [\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n    indirect=True,\n)\ndef test_tutorial004(print_mock: PrintMock, module: ModuleType):\n    module.main()\n    assert print_mock.calls == expected_calls\n"
  },
  {
    "path": "tests/test_tutorial/test_where/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"age\": None,\n                \"id\": 1,\n            }\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial002.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            {\n                \"name\": \"Spider-Boy\",\n                \"secret_name\": \"Pedro Parqueador\",\n                \"age\": None,\n                \"id\": 2,\n            }\n        ],\n        [{\"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48, \"id\": 3}],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial003.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n\n    expected_calls = [\n        [{\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36}],\n        [{\"id\": 3, \"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48}],\n        [\n            {\n                \"id\": 7,\n                \"name\": \"Captain North America\",\n                \"secret_name\": \"Esteban Rogelios\",\n                \"age\": 93,\n            }\n        ],\n    ]\n    calls = print_mock.calls\n    for call in expected_calls:\n        assert call in calls, \"This expected item should be in the list\"\n        # Now that this item was checked, remove it from the list\n        calls.pop(calls.index(call))\n    assert len(calls) == 0, \"The list should only have the expected items\"\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    expected_calls = [\n        [{\"id\": 5, \"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35}],\n        [{\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36}],\n        [{\"id\": 3, \"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48}],\n        [\n            {\n                \"id\": 7,\n                \"name\": \"Captain North America\",\n                \"secret_name\": \"Esteban Rogelios\",\n                \"age\": 93,\n            }\n        ],\n    ]\n    calls = print_mock.calls\n    for call in expected_calls:\n        assert call in calls, \"This expected item should be in the list\"\n        # Now that this item was checked, remove it from the list\n        calls.pop(calls.index(call))\n    assert len(calls) == 0, \"The list should only have the expected items\"\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial005.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"name\": \"Tarantula\", \"secret_name\": \"Natalia Roman-on\", \"age\": 32, \"id\": 4}]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial006.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial006_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"name\": \"Tarantula\", \"secret_name\": \"Natalia Roman-on\", \"age\": 32, \"id\": 4}],\n        [{\"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35, \"id\": 5}],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial006b.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial006b_py39\"),\n        pytest.param(\"tutorial006b_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [\n            {\n                \"name\": \"Deadpond\",\n                \"secret_name\": \"Dive Wilson\",\n                \"age\": None,\n                \"id\": 1,\n            }\n        ]\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial007.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial007_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"id\": 5, \"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35}],\n        [{\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36}],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial008.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial008_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"id\": 5, \"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35}],\n        [{\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36}],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial009.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial009_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    assert print_mock.calls == [\n        [{\"name\": \"Tarantula\", \"secret_name\": \"Natalia Roman-on\", \"age\": 32, \"id\": 4}],\n        [{\"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35, \"id\": 5}],\n        [\n            {\n                \"name\": \"Captain North America\",\n                \"secret_name\": \"Esteban Rogelios\",\n                \"age\": 93,\n                \"id\": 7,\n            }\n        ],\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_where/test_tutorial011.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom sqlmodel import create_engine\n\nfrom ...conftest import PrintMock, needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial011_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod = importlib.import_module(f\"docs_src.tutorial.where.{request.param}\")\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(mod.sqlite_url)\n    return mod\n\n\ndef test_tutorial(print_mock: PrintMock, mod: ModuleType):\n    mod.main()\n    expected_calls = [\n        [{\"id\": 5, \"name\": \"Black Lion\", \"secret_name\": \"Trevor Challa\", \"age\": 35}],\n        [{\"id\": 6, \"name\": \"Dr. Weird\", \"secret_name\": \"Steve Weird\", \"age\": 36}],\n        [{\"id\": 3, \"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\", \"age\": 48}],\n        [\n            {\n                \"id\": 7,\n                \"name\": \"Captain North America\",\n                \"secret_name\": \"Esteban Rogelios\",\n                \"age\": 93,\n            }\n        ],\n    ]\n    calls = print_mock.calls\n    for call in expected_calls:\n        assert call in calls, \"This expected item should be in the list\"\n        # Now that this item was checked, remove it from the list\n        calls.pop(calls.index(call))\n    assert len(calls) == 0, \"The list should only have the expected items\"\n"
  },
  {
    "path": "tests/test_update.py",
    "content": "from sqlmodel import Field, SQLModel\n\n\ndef test_sqlmodel_update():\n    class Organization(SQLModel, table=True):\n        id: int = Field(default=None, primary_key=True)\n        name: str\n        headquarters: str\n\n    class OrganizationUpdate(SQLModel):\n        name: str\n\n    org = Organization(name=\"Example Org\", city=\"New York\", headquarters=\"NYC HQ\")\n    org_in = OrganizationUpdate(name=\"Updated org\")\n    org.sqlmodel_update(\n        org_in,\n        update={\n            \"headquarters\": \"-\",  # This field is in Organization, but not in OrganizationUpdate\n        },\n    )\n"
  },
  {
    "path": "tests/test_validation.py",
    "content": "import pytest\nfrom pydantic.error_wrappers import ValidationError\nfrom sqlmodel import SQLModel\n\n\ndef test_validation_pydantic_v2(clear_sqlmodel):\n    \"\"\"Test validation of implicit and explicit None values.\n\n    # For consistency with pydantic, validators are not to be called on\n    # arguments that are not explicitly provided.\n\n    https://github.com/tiangolo/sqlmodel/issues/230\n    https://github.com/samuelcolvin/pydantic/issues/1223\n\n    \"\"\"\n    from pydantic import field_validator\n\n    class Hero(SQLModel):\n        name: str | None = None\n        secret_name: str | None = None\n        age: int | None = None\n\n        @field_validator(\"name\", \"secret_name\", \"age\")\n        def reject_none(cls, v):\n            assert v is not None\n            return v\n\n    Hero.model_validate({\"age\": 25})\n\n    with pytest.raises(ValidationError):\n        Hero.model_validate({\"name\": None, \"age\": 25})\n"
  }
]