Showing preview only (1,288K chars total). Download the full file or copy to clipboard to get everything.
Repository: chrisglass/django_polymorphic
Branch: main
Commit: aa79885c7111
Files: 240
Total size: 1.2 MB
Directory structure:
gitextract_t9wkysva/
├── .github/
│ ├── CODEOWNERS
│ ├── dependabot.yml
│ └── workflows/
│ ├── bandit.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── scorecard.yml
│ ├── test.yml
│ ├── update_coc.yml
│ └── zizmor.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── AUTHORS.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── conftest.py
├── docs/
│ ├── _ext/
│ │ └── djangodummy/
│ │ ├── __init__.py
│ │ ├── requirements.txt
│ │ └── settings.py
│ ├── _static/
│ │ ├── .gitkeep
│ │ └── style.css
│ ├── admin.rst
│ ├── advanced.rst
│ ├── api/
│ │ ├── index.rst
│ │ ├── polymorphic.admin.rst
│ │ ├── polymorphic.contrib/
│ │ │ ├── drf.rst
│ │ │ ├── extra_views.rst
│ │ │ ├── guardian.rst
│ │ │ └── index.rst
│ │ ├── polymorphic.deletion.rst
│ │ ├── polymorphic.formsets.rst
│ │ ├── polymorphic.managers.rst
│ │ ├── polymorphic.models.rst
│ │ ├── polymorphic.showfields.rst
│ │ ├── polymorphic.templatetags/
│ │ │ ├── index.rst
│ │ │ ├── polymorphic_admin_tags.rst
│ │ │ └── polymorphic_formset_tags.rst
│ │ └── polymorphic.utils.rst
│ ├── changelog/
│ │ ├── drf.rst
│ │ └── index.rst
│ ├── conf.py
│ ├── deletion.rst
│ ├── formsets.rst
│ ├── index.rst
│ ├── integrations/
│ │ ├── drf.rst
│ │ └── index.rst
│ ├── managers.rst
│ ├── migrating.rst
│ ├── performance.rst
│ ├── quickstart.rst
│ ├── typing.rst
│ └── views.rst
├── example/
│ ├── example/
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ ├── orders/
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ └── models.py
│ └── pexp/
│ ├── __init__.py
│ ├── admin.py
│ ├── dumpdata_test_correct_output.txt
│ ├── management/
│ │ ├── __init__.py
│ │ └── commands/
│ │ ├── __init__.py
│ │ ├── p2cmd.py
│ │ ├── pcmd.py
│ │ ├── polybench.py
│ │ └── polymorphic_create_test_data.py
│ ├── migrations/
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ └── models.py
├── justfile
├── manage.py
├── pyproject.toml
└── src/
└── polymorphic/
├── __init__.py
├── admin/
│ ├── __init__.py
│ ├── childadmin.py
│ ├── filters.py
│ ├── forms.py
│ ├── generic.py
│ ├── helpers.py
│ ├── inlines.py
│ └── parentadmin.py
├── apps.py
├── base.py
├── contrib/
│ ├── __init__.py
│ ├── drf/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── serializers.py
│ ├── extra_views.py
│ └── guardian.py
├── deletion.py
├── formsets/
│ ├── __init__.py
│ ├── generic.py
│ ├── models.py
│ └── utils.py
├── locale/
│ ├── en/
│ │ └── LC_MESSAGES/
│ │ └── django.po
│ ├── es/
│ │ └── LC_MESSAGES/
│ │ └── django.po
│ └── fr/
│ └── LC_MESSAGES/
│ └── django.po
├── managers.py
├── models.py
├── py.typed
├── query.py
├── query_translate.py
├── related_descriptors.py
├── showfields.py
├── static/
│ └── polymorphic/
│ ├── css/
│ │ └── polymorphic_inlines.css
│ └── js/
│ └── polymorphic_inlines.js
├── templates/
│ └── admin/
│ └── polymorphic/
│ ├── add_type_form.html
│ ├── change_form.html
│ ├── delete_confirmation.html
│ ├── edit_inline/
│ │ └── stacked.html
│ └── object_history.html
├── templatetags/
│ ├── __init__.py
│ ├── polymorphic_admin_tags.py
│ └── polymorphic_formset_tags.py
├── tests/
│ ├── __init__.py
│ ├── admin.py
│ ├── admintestcase.py
│ ├── conftest.py
│ ├── debug.py
│ ├── deletion/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_deletion.py
│ ├── errata/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── settings.py
│ │ └── test_errata.py
│ ├── examples/
│ │ ├── __init__.py
│ │ ├── integrations/
│ │ │ ├── __init__.py
│ │ │ ├── apps.py
│ │ │ ├── drf/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── example_serializers.py
│ │ │ │ ├── filter_serializers.py
│ │ │ │ ├── filter_views.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── example_models.py
│ │ │ │ │ ├── filters.py
│ │ │ │ │ └── models_test.py
│ │ │ │ ├── serializers.py
│ │ │ │ ├── test.py
│ │ │ │ ├── urls.py
│ │ │ │ └── views.py
│ │ │ ├── extra_views/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── templates/
│ │ │ │ │ └── extra_views/
│ │ │ │ │ └── article_formset.html
│ │ │ │ ├── templatetags/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── extra_views_tags.py
│ │ │ │ ├── test.py
│ │ │ │ ├── urls.py
│ │ │ │ └── views.py
│ │ │ ├── guardian/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ └── test.py
│ │ │ ├── migrations/
│ │ │ │ ├── 0001_initial.py
│ │ │ │ └── __init__.py
│ │ │ ├── models.py
│ │ │ └── reversion/
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── apps.py
│ │ │ ├── templates/
│ │ │ │ └── admin/
│ │ │ │ └── polymorphic/
│ │ │ │ └── object_history.html
│ │ │ └── test.py
│ │ ├── type_hints/
│ │ │ ├── __init__.py
│ │ │ ├── fk/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── m2m/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── managers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── models.py
│ │ │ ├── one2one/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ └── pyright.json
│ │ └── views/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── templates/
│ │ │ ├── project_form.html
│ │ │ └── project_type_select.html
│ │ ├── test.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── migrations/
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── other/
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_cross_apps.py
│ ├── settings.py
│ ├── test_admin.py
│ ├── test_base.py
│ ├── test_contrib.py
│ ├── test_formsets.py
│ ├── test_inheritance.py
│ ├── test_migration_managers.py
│ ├── test_migrations/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_on_delete.py
│ ├── test_multidb.py
│ ├── test_orm.py
│ ├── test_performance.py
│ ├── test_query_translate.py
│ ├── test_regression.py
│ ├── test_serialization.py
│ ├── test_signals.py
│ ├── test_templatetags.py
│ ├── test_utils.py
│ ├── urls.py
│ └── utils.py
└── utils.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/CODEOWNERS
================================================
# Default: everything
* @bckohan
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
groups:
gha-updates:
patterns:
- "*"
================================================
FILE: .github/workflows/bandit.yml
================================================
name: Bandit
on:
push:
branches: [ main ]
pull_request:
paths:
- "src/**"
- "pyproject.toml"
- "justfile"
- ".github/workflows/bandit.yml"
workflow_dispatch:
permissions:
contents: read
jobs:
bandit-analysis:
name: Run Bandit
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: '3.x'
allow-prereleases: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Install Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Run Bandit
run: |
just bandit
- name: Upload analysis results
if: ${{ always() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: bandit-results
path: bandit.sarif
retention-days: 7
- name: Upload to code-scanning
if: ${{ always() }}
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7
with:
sarif_file: bandit.sarif
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
permissions:
contents: read
on:
push:
tags-ignore:
- '*'
branches:
- '*'
pull_request:
workflow_call:
workflow_dispatch:
inputs:
debug:
description: 'Open ssh debug session.'
required: true
default: false
type: boolean
jobs:
lint:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
# run static analysis on bleeding and trailing edges
python-version: ['3.10', '3.12', '3.14']
django-version:
- 'dj42' # LTS April 2026
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.14'
django-version: 'dj52'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj60'
env:
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Install Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Run Static Analysis
env:
PYTHON_PATH: ${{ steps.sp.outputs.python-path }}
run: |
just check -p "$PYTHON_PATH" --group "$TEST_DJANGO_VERSION"
================================================
FILE: .github/workflows/release.yml
================================================
name: Publish Release
permissions: read-all
concurrency:
# stop previous release runs if tag is recreated
group: release-${{ github.ref }}
cancel-in-progress: true
on:
push:
tags:
- "v[0-9]*.[0-9]*.[0-9]*" # only publish on version tags (e.g. v1.0.0)
jobs:
lint:
permissions:
contents: read
actions: write
uses: ./.github/workflows/lint.yml
test:
permissions:
contents: read
actions: write
id-token: write
uses: ./.github/workflows/test.yml
build:
name: Build Package
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
outputs:
PACKAGE_NAME: ${{ steps.set-package.outputs.package_name }}
RELEASE_VERSION: ${{ steps.set-package.outputs.release_version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.14" # for tomlib
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
restore-cache: false
save-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Verify Tag
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
echo "Verifying tag $TAG_NAME..."
# if a tag was deleted and recreated we may have the old one cached
# be sure that we're publishing the current tag!
git fetch --force origin refs/tags/$TAG_NAME:refs/tags/$TAG_NAME
# verify signature
curl -sL "https://github.com/${GITHUB_ACTOR}.gpg" | gpg --import
git tag -v "$TAG_NAME"
# verify version
RELEASE_VERSION=$(just validate_version $TAG_NAME)
# export the release version
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV
- name: Install gettext
run: sudo apt-get install -y gettext
- name: Build the binary wheel and a source tarball
run: just build
- name: Store the distribution packages
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: python-package-distributions
path: dist/
- name: Set Package Name
id: set-package
run:
PACKAGE_NAME=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['name'])")
echo "PACKAGE_NAME=${PACKAGE_NAME}" >> $GITHUB_ENV
publish-to-pypi:
name: Publish to PyPI
needs:
- lint
- test
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/${{ needs.build.outputs.PACKAGE_NAME }}
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
github-release:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs:
- lint
- test
- build
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore
steps:
- name: Download all the dists
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: python-package-distributions
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@04cffa1d795717b140764e8b640de88853c92acc
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: >-
gh release create
"$GITHUB_REF_NAME"
--repo "$GITHUB_REPOSITORY"
--generate-notes
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_REPOSITORY: ${{ github.repository }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
"$GITHUB_REF_NAME" dist/**
--repo "$GITHUB_REPOSITORY"
# chrisglass owns this: https://test.pypi.org/project/django-polymorphic/
# publish-to-testpypi:
# name: Publish to TestPyPI
# needs:
# - build
# runs-on: ubuntu-latest
# environment:
# name: testpypi
# url: https://test.pypi.org/project/${{ needs.build.outputs.PACKAGE_NAME }}
# permissions:
# id-token: write # IMPORTANT: mandatory for trusted publishing
# steps:
# - name: Download all the dists
# uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
# with:
# name: python-package-distributions
# path: dist/
# - name: Publish distribution 📦 to TestPyPI
# uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
# with:
# repository-url: https://test.pypi.org/legacy/
# skip-existing: true
================================================
FILE: .github/workflows/scorecard.yml
================================================
name: OpenSSF Scorecard
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
push:
branches: [ main ]
workflow_dispatch:
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
environment:
name: scorecard
deployment: false # Prevents creating a GitHub deployment object
permissions:
security-events: write
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7
with:
sarif_file: results.sarif
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
permissions:
contents: read
on:
push:
tags-ignore:
- '*'
branches: ['main']
pull_request:
branches: ['main']
paths:
- "src/**"
- ".github/workflows/test.yml"
- "pyproject.toml"
- "justfile"
merge_group:
workflow_call:
workflow_dispatch:
inputs:
debug:
description: 'Open ssh debug session.'
required: true
default: false
type: boolean
clear_cache:
description: 'Clear GitHub Tool cache.'
required: true
default: false
type: boolean
schedule:
# Every Sunday at 9:00 AM Los Angeles time.
# GitHub cron is UTC; 09:00 PT == 17:00 UTC (PST).
- cron: '0 17 * * 0'
jobs:
postgres:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
# Service containers to run with `container-job`
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
postgres-version: ['12', '14', 'latest']
psycopg-version: ['psycopg2', 'psycopg3']
django-version:
- 'dj42' # LTS April 2026
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.11'
django-version: 'dj60'
- python-version: '3.13'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj52'
- postgres-version: '12'
django-version: 'dj52'
- postgres-version: '12'
django-version: 'dj60'
- postgres-version: '14'
django-version: 'dj42'
- postgres-version: '14'
django-version: 'dj52'
- postgres-version: '14'
django-version: 'dj60'
- postgres-version: 'latest'
django-version: 'dj42'
- postgres-version: '12'
psycopg-version: 'psycopg3'
- postgres-version: 'latest'
psycopg-version: 'psycopg2'
# https://github.com/psycopg/psycopg2/pull/1695
- python-version: '3.13'
psycopg-version: 'psycopg2'
- python-version: '3.14'
psycopg-version: 'psycopg2'
env:
RDBMS: postgres
POSTGRES_PASSWORD: postgres
PGPASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
COVERAGE_FILE: linux-py${{ matrix.python-version }}-${{ matrix.django-version }}-${{ matrix.psycopg-version }}-pg${{ matrix.postgres-version }}.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_CLIENT_VERSION: ${{ matrix.psycopg-version }}
TEST_DATABASE_VERSION: ${{ matrix.postgres-version }}
# Service containers to run with `runner-job`
services:
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres:${{ matrix.postgres-version }}
# Provide the password for postgres
env:
POSTGRES_PASSWORD: postgres
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
id: sp
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Create test databases
run: |
psql -h localhost -p 5432 -U postgres -d postgres -c "CREATE DATABASE test1;"
psql -h localhost -p 5432 -U postgres -d postgres -c "CREATE DATABASE test2;"
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all --group "${{ matrix.psycopg-version }}" -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
sqlite:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
env:
RDBMS: sqlite
COVERAGE_FILE: linux-py${{ matrix.python-version }}-${{ matrix.django-version }}-sqlite.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_VERSION: "sqlite"
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.12', '3.14']
django-version:
- 'dj42' # LTS April 2026
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.12'
django-version: 'dj60'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj52'
steps:
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
mysql:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.12', '3.14']
mysql-version: ['8.0', 'latest']
mysqlclient-version: ['mysqlclient14', 'mysqlclient2x']
django-version:
- 'dj42' # LTS April 2024
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- django-version: 'dj42'
mysql-version: 'latest'
- django-version: 'dj60'
mysql-version: '8.0'
- mysql-version: 'latest'
mysqlclient-version: 'mysqlclient14'
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.14'
django-version: 'dj52'
- django-version: 'dj52'
mysqlclient-version: 'mysqlclient14'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj60'
env:
RDBMS: mysql
MYSQL_VERSION: ${{ matrix.mysql-version }}
COVERAGE_FILE: linux-py${{ matrix.python-version }}-${{ matrix.django-version }}-${{ matrix.mysqlclient-version }}-mysql${{ matrix.mysql-version }}.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_CLIENT_VERSION: ${{ matrix.mysqlclient-version }}
TEST_DATABASE_VERSION: ${{ matrix.mysql-version }}
services:
mysql:
# Docker Hub image
image: mysql:${{ matrix.mysql-version }}
# Provide the password for mysql
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_MULTIPLE_DATABASES: test1,test2
# Set health checks to wait until mysql has started
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 3306 on service container to the host
- 3306:3306
steps:
# make text comparisons case sensitive (some tests)
- name: Set default collation for MySQL
run: |
mysql -h 127.0.0.1 -u root -proot <<EOF
SET GLOBAL character_set_server='utf8mb4';
SET GLOBAL collation_server='utf8mb4_0900_as_cs';
EOF
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all --group "${{ matrix.mysqlclient-version }}" -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
mariadb:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
env:
RDBMS: mariadb
COVERAGE_FILE: linux-py${{ matrix.python-version }}-${{ matrix.django-version }}-${{ matrix.mysqlclient-version }}-mariadb${{ matrix.mariadb-version }}.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_CLIENT_VERSION: ${{ matrix.mysqlclient-version }}
TEST_DATABASE_VERSION: ${{ matrix.mariadb-version }}
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.12', '3.14']
mysqlclient-version: ['mysqlclient14', 'mysqlclient2x']
mariadb-version: ['10.4', 'latest']
mariadb-healthcheck: ["mysqladmin ping", "healthcheck.sh --connect --innodb_initialized"]
django-version:
- 'dj42' # LTS April 2024
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- django-version: 'dj42'
mariadb-version: 'latest'
- django-version: 'dj52'
mariadb-version: '10.4'
- django-version: 'dj60'
mariadb-version: '10.4'
- mariadb-version: 'latest'
mysqlclient-version: 'mysqlclient14'
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.14'
django-version: 'dj52'
- django-version: 'dj52'
mysqlclient-version: 'mysqlclient14'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj60'
- mariadb-version: '10.4'
mysqlclient-version: 'mysqlclient2x'
- mariadb-version: 'latest'
mariadb-healthcheck: "mysqladmin ping"
- mariadb-version: '10.4'
mariadb-healthcheck: "healthcheck.sh --connect --innodb_initialized"
services:
mariadb:
# Docker Hub image
image: mariadb:${{ matrix.mariadb-version }}
# Provide the password for mysql
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_MULTIPLE_DATABASES: test1,test2
# Set health checks to wait until mysql has started
options: >-
--health-cmd="${{ matrix.mariadb-healthcheck }}"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 3306 on service container to the host
- 3306:3306
steps:
# make text comparisons case sensitive (some tests)
- name: Set default collation for MariaDB
run: |
mysql -h 127.0.0.1 -u root -proot <<EOF
SET GLOBAL character_set_server='utf8mb4';
SET GLOBAL collation_server='utf8mb4_bin';
EOF
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all --group "${{ matrix.mysqlclient-version }}" -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
oracle:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
env:
RDBMS: oracle
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_VERSION: ${{ matrix.oracle-version }}
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.14']
django-version:
- 'dj42' # LTS April 2026
- 'dj52' # LTS April 2028
- 'dj60' #
oracle-version:
- 'oracle-xe:21'
- 'oracle-free:latest'
exclude:
- django-version: 'dj42'
oracle-version: 'oracle-free:latest'
- django-version: 'dj52'
oracle-version: 'oracle-free:latest'
- django-version: 'dj60'
oracle-version: 'oracle-xe:21'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj52'
services:
oracle1:
image: gvenzl/${{ matrix.oracle-version }} # zizmor: ignore[unpinned-images]
env:
ORACLE_PASSWORD: password
ORACLE_DATABASE: test1
# Forward Oracle port
ports:
- 1521:1521
# Provide healthcheck script options for startup
options: >-
--health-cmd healthcheck.sh
--health-interval 10s
--health-timeout 5s
--health-retries 10
oracle2:
image: gvenzl/${{ matrix.oracle-version }} # zizmor: ignore[unpinned-images]
env:
ORACLE_PASSWORD: password
ORACLE_DATABASE: test2
# Forward Oracle port
ports:
- 1522:1521
# Provide healthcheck script options for startup
options: >-
--health-cmd healthcheck.sh
--health-interval 10s
--health-timeout 5s
--health-retries 10
steps:
- name: Set coverage file
run: |
ORACLE_TAG=$(echo "${{ matrix.oracle-version }}" | cut -d':' -f2)
echo "COVERAGE_FILE=linux-py${{ matrix.python-version }}-${{ matrix.django-version }}-oracle${ORACLE_TAG}.coverage" >> $GITHUB_ENV
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
id: sp
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install Emacs
if: ${{ github.event.inputs.debug == 'true' }}
run: |
sudo apt install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Install Oracle Client
# https://askubuntu.com/questions/1512196/libaio1-on-noble
run: |
sudo apt install alien libaio1t64
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
if [[ "${{ matrix.oracle-version }}" == oracle-xe* ]]; then
curl --output oracle-client.rpm https://download.oracle.com/otn_software/linux/instantclient/2116000/oracle-instantclient-basiclite-21.16.0.0.0-1.el8.x86_64.rpm
sudo alien -i oracle-client.rpm
sudo sh -c "echo /usr/lib/oracle/21/client64/lib/ > /etc/ld.so.conf.d/oracle.conf"
else
curl --output oracle-client.rpm https://download.oracle.com/otn_software/linux/instantclient/2326000/oracle-instantclient-basiclite-23.26.0.0.0-1.el9.x86_64.rpm
sudo alien -i oracle-client.rpm
sudo sh -c "echo /usr/lib/oracle/23/client64/lib/ > /etc/ld.so.conf.d/oracle.conf"
fi
sudo ldconfig
# we don't run integration tests against Oracle in CI, these are slow enough
- name: Run Full Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
if [[ "${{ matrix.oracle-version }}" == oracle-xe* ]]; then
just test-all --group cx_oracle -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
else
just test-all --group oracledb -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
fi
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
windows:
runs-on: windows-latest
permissions:
contents: read
actions: write
env:
RDBMS: sqlite
COVERAGE_FILE: windows-py${{ matrix.python-version }}-${{ matrix.django-version }}-sqlite.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_VERSION: "sqlite"
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.12', '3.14']
django-version:
- 'dj42' # LTS April 2026
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.12'
django-version: 'dj60'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj52'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: install-vim-windows
if: ${{ github.event.inputs.debug == 'true' }}
uses: rhysd/action-setup-vim@febef33995d6649302e9d88dda81e071b68f16a7
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all -p "$env:TEST_PYTHON" --group "$env:TEST_DJANGO_VERSION"
shell: pwsh
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
macos:
runs-on: macos-latest
permissions:
contents: read
actions: write
env:
RDBMS: sqlite
COVERAGE_FILE: macos-py${{ matrix.python-version }}-${{ matrix.django-version }}-sqlite.coverage
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
TEST_DATABASE_VERSION: "sqlite"
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.12', '3.14']
django-version:
- 'dj42' # LTS April 2024
- 'dj52' # LTS April 2028
- 'dj60' #
exclude:
- python-version: '3.10'
django-version: 'dj52'
- python-version: '3.10'
django-version: 'dj60'
- python-version: '3.12'
django-version: 'dj42'
- python-version: '3.12'
django-version: 'dj60'
- python-version: '3.14'
django-version: 'dj42'
- python-version: '3.14'
django-version: 'dj52'
steps:
- name: Clear Tool cache
if: ${{ github.event.inputs.clear_cache == 'true' }}
run: sudo rm -rf /opt/hostedtoolcache
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: install-emacs-macos
if: ${{ github.event.inputs.debug == 'true' }}
run: |
brew install emacs
- name: Setup tmate session
if: ${{ github.event.inputs.debug == 'true' }}
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101
timeout-minutes: 60
- name: Run Unit Tests
env:
TEST_PYTHON: ${{ steps.sp.outputs.python-path }}
run: |
just test-all -p "$TEST_PYTHON" --group "$TEST_DJANGO_VERSION"
- name: Store coverage files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COVERAGE_FILE }}
path: ${{ env.COVERAGE_FILE }}
coverage-combine:
needs: [postgres, sqlite, mysql, mariadb, oracle, windows, macos]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
id: sp
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b
with:
enable-cache: false
- name: Setup Just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3
- name: Get coverage files
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
pattern: "*.coverage"
merge-multiple: true
- run: ls -la *.coverage
- run: just coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
with:
use_oidc: true
files:
./coverage.xml
================================================
FILE: .github/workflows/update_coc.yml
================================================
name: Update Code of Conduct
permissions: read-all
on:
workflow_dispatch:
# Run every Sunday at midnight UTC (00:00) - triggered by webhook?
schedule:
- cron: '0 0 * * SUN'
jobs:
update_code_of_conduct:
permissions:
contents: write
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Fetch CODE_OF_CONDUCT.md from django-commons
run: |
curl -o fetched_code_of_conduct.md https://raw.githubusercontent.com/django-commons/membership/main/CODE_OF_CONDUCT.md
- name: Check if CODE_OF_CONDUCT.md has changed
id: check_changes
run: |
if cmp -s fetched_code_of_conduct.md CODE_OF_CONDUCT.md; then
echo "No changes in CODE_OF_CONDUCT.md"
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "CODE_OF_CONDUCT.md has changed"
echo "changed=true" >> $GITHUB_OUTPUT
cp fetched_code_of_conduct.md CODE_OF_CONDUCT.md
fi
# Create a pull request to merge the changes into the main branch
- name: Create Pull Request
if: steps.check_changes.outputs.changed == 'true'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: bot-update-coc
add-paths: |
CODE_OF_CONDUCT.md
title: "🤖 Update Code of Conduct 🤖"
body: "Update the Code of Conduct with the latest version from the django-commons repository."
commit-message: "Update CODE_OF_CONDUCT.md from django-commons"
================================================
FILE: .github/workflows/zizmor.yml
================================================
name: Zizmor
on:
push:
branches: [ main ]
pull_request:
paths:
- ".github/workflows/**/*.yml"
schedule:
# Run weekly
- cron: '0 0 * * 0'
workflow_dispatch:
permissions:
contents: read
jobs:
zizmor-analysis:
name: Run Zizmor
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7
- name: Install jq
run: |
sudo apt-get update
sudo apt-get install -y jq
- name: Install Zizmor
run: |
cargo install --locked zizmor
- name: Run Zizmor analysis
run: |
zizmor --format sarif .github/workflows/ > zizmor.sarif
- name: Upload analysis results
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: zizmor-results
path: zizmor.sarif
retention-days: 7
- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7
with:
sarif_file: zizmor.sarif
- name: Fail on Findings
run: |
count="$(
jq '([.runs[]? | (.results // [])[] | select(.level != "note")] | length) // 0' \
zizmor.sarif
)"
echo "Zizmor findings: $count"
test "$count" -eq 0
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Test migrations (generated dynamically by tests)
src/polymorphic/tests/test_migrations/migrations/0*.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
#poetry.toml
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/
# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# Redis
*.rdb
*.aof
*.pid
# RabbitMQ
mnesia/
rabbitmq/
rabbitmq-data/
# ActiveMQ
activemq-data/
# SageMath parsed files
*.sage.py
# Environments
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/
# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/
# Streamlit
.streamlit/secrets.toml
.DS_Store
.python-version
test1.db
test2.db
example/example.db
CLAUDE.md
zizmor.sarif
bandit.sarif
================================================
FILE: .pre-commit-config.yaml
================================================
ci:
# Don't run these in pre-commit.ci at all
skip: [lint, format, docs, pip]
repos:
- repo: local
hooks:
- id: lint
name: Lint
entry: just lint
language: system
pass_filenames: false
- id: format
name: Format
entry: just format
language: system
pass_filenames: false
- id: docs
name: Docs
entry: just check-docs
language: system
pass_filenames: false
- id: pip
name: Package
entry: just check-package
language: system
pass_filenames: false
================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
apt_packages:
- gettext
jobs:
post_install:
- pip install uv
- UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --all-extras --group docs --link-mode=copy
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
formats:
- pdf
================================================
FILE: AUTHORS.md
================================================
# Current Maintainer(s)
* Brian Kohan
## Contributors
* Abel Daniel
* Adam Chainz
* Adam Wentz
* Adam Donaghy
* Andrew Ingram (contributed setup.py)
* Al Johri
* Alex Alvarez
* Andrew Dodd
* Angel Velasquez
* Austin Matsick
* Bastien Vallet
* Ben Konrath
* Bert Constantin
* Bertrand Bordage
* Chad Shryock
* Charles Leifer (python 2.4 compatibility)
* Chris Barna
* Chris Brantley
* Christopher Glass
* David Sanders
* Emad Rad
* Éric Araujo
* Evan Borgstrom
* Frankie Dintino
* Gavin Wahl
* Germán M. Bravo
* Gonzalo Bustos
* Gregory Avery-Weir
* Hugo Osvaldo Barrera
* Jacob Rief
* James Murty
* Jedediah Smith (proxy models support)
* Jesús Leganés-Combarro (Auto-discover child models and inlines, #582)
* John Furr
* Jonas Haag
* Jonas Obrist
* Julian Wachholz
* Kamil Bar
* Kelsey Gilmore-Innis
* Kevin Armenat
* Krzysztof Gromadzki
* Krzysztof Nazarewski
* Luis Zárate
* Marius Lueck
* Martin Brochhaus
* Martin Maillard
* Michael Fladischer
* Nick Ward
* Oleg Myltsyn
* Omer Strumpf
* Paweł Adamczak
* Petr Dlouhý
* Sander van Leeuwen
* Sobolev Nikita
* Tadas Dailyda
* Tai Lee
* Tomas Peterka
* Tony Narlock
* Vail Gold
## Former authors / maintainers
* Bert Constantin 2009/2010 (Original author, disappeared from the internet :( )
* Chris Glass
* Diederik van der Boor
* Charlie Denton
* Jerome Leclanche
## django-rest-framework
### Development Lead
* Denis Orehovsky <denis.orehovsky@gmail.com>
### Contributors
* Jeff Hackshaw <jeffrey.hackshaw@gmail.com>
* TFranzel
* Ignacio Losiggio <iglosiggio@gmail.com>
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Django Commons Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[django-commons-coc@googlegroups.com](mailto:django-commons-coc@googlegroups.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Warning
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 2. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 3. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Contributions are encouraged! Please use the issue page to submit feature requests or bug reports. Issues with attached PRs will be given priority and have a much higher likelihood of acceptance. Please also open an issue and associate it with any submitted PRs.
This is a [django-commons](https://django-commons.org) project. If you wish to contribute, [please join the organization!](https://django-commons.org/#how-to-join-as-a-contributor)
We are actively seeking additional maintainers. If you're interested, please open an issue or [contact me](https://github.com/bckohan).
## Installation
### Install Just
We provide a platform independent justfile with recipes for all the development tasks. You should [install just](https://just.systems/man/en/) if it is not on your system already.
[django-polymorphic](https://pypi.python.org/pypi/django-polymorphic) uses [uv](https://docs.astral.sh/uv) for environment, package, and dependency management. ``just setup`` will install the necessary build tooling if you do not already have it:
```bash
just setup
```
Setup also may take a python version:
```bash
just setup 3.12
```
If you already have uv and python installed running install will just install the development dependencies:
```bash
just install
```
**To run pre-commit checks you will have to install just.**
## Documentation
`django-polymorphic` documentation is generated using [Sphinx](https://www.sphinx-doc.org) with the [furo](https://github.com/pradyunsg/furo) theme. Any new feature PRs must provide updated documentation for the features added. To build the docs run doc8 to check for formatting issues then run Sphinx:
```bash
just docs # builds docs
just check-docs # lint the docs
just check-docs-links # check for broken links in the docs
```
Run the docs with auto rebuild using:
```bash
just docs-live
```
## Static Analysis
`django-polymorphic` uses [ruff](https://docs.astral.sh/ruff/) for Python linting, header import standardization and code formatting. Before any PR is accepted the following must be run, and static analysis tools should not produce any errors or warnings. Disabling certain errors or warnings where justified is acceptable:
To fix formatting and linting problems that are fixable run:
```bash
just fix
```
To run all static analysis without automated fixing you can run:
```bash
just check
```
To format source files you can run:
```bash
just format
```
### Type Checking
Both [mypy](https://www.mypy-lang.org) and [pyright](https://microsoft.github.io/pyright) are used to verify static typing. You can run them together or individually:
```bash
just check-types
just check-types-mypy
just check-types-pyright
```
## Running Tests
`django-polymorphic` is set up to use [pytest](https://docs.pytest.org) to run unit tests. All the tests are housed in `src/polymorphic/tests`. Before a PR is accepted, all tests must be passing and the code coverage must be at 100%. A small number of exempted error handling branches are acceptable.
To run the full suite:
```bash
just test
```
To run a single test, or group of tests in a class:
```bash
just test <path_to_tests_file>::ClassName::FunctionName
```
For instance, to run all admin tests, and then just the test_admin_registration test you would do:
```bash
just test src/polymorphic/tests/test_admin.py
just test src/polymorphic/tests/test_admin.py::PolymorphicAdminTests::test_admin_registration
```
### Running UI Tests
Make sure you have playwright installed:
```bash
just install-playwright
```
If you want to see the test step through the UI actions you can run the test like so:
```bash
just debug-test -k <test_name>
```
This will open a browser and the debugger at the start of the test, you can then ``next`` through and see the UI actions happen.
## Versioning
[django-polymorphic](https://pypi.python.org/pypi/django-polymorphic) strictly adheres to [semantic versioning](https://semver.org).
## Issuing Releases
The release workflow is triggered by tag creation. You must have [git tag signing enabled](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits). Our justfile has a release shortcut:
```bash
just release x.x.x
```
## Just Recipes
```bash
build # build docs and package
build-docs # build the docs
build-docs-html # build html documentation
build-docs-pdf # build pdf documentation
check # run all static checks
check-all # run all checks including doc link staleness (slow)
check-docs # lint the documentation
check-docs-links # check the documentation links for broken links
check-format # check if the code needs formatting
check-lint # lint the code
check-package # run package checks
check-readme # check that the readme renders
check-types # run all static type checking
check-types-isolated # run all static type checking in an isolated environment
check-types-mypy *RUN_ARGS # run static type checking with mypy
check-types-pyright *RUN_ARGS # run static type checking with pyright
clean # remove all non repository artifacts
clean-docs # remove doc build artifacts-
clean-env # remove the virtual environment
clean-git-ignored # remove all git ignored files
coverage # generate the test coverage report
debug-test *TESTS # debug an test
docs # build and open the documentation
docs-live # serve the documentation, with auto-reload
fetch-refs LIB # get the intersphinx references for the given library
fix # fix formatting, linting issues and import sorting
format # format the code and sort imports
install *OPTS # update and install development dependencies
install-playwright # install playwright dependencies
install-precommit # install git pre-commit hooks
install_uv # install the uv package manager
lint # sort the imports and fix linting issues
manage *COMMAND # run the django admin
open-docs # open the html documentation
precommit # run the pre-commit checks
release VERSION # issue a release for the given semver string (e.g. 2.1.0)
remake-test-migrations # regenerate test migrations using the lowest version of Django
run +ARGS # run the command in the virtual environment
setup python="python" # setup the venv, pre-commit hooks and playwright dependencies
sort-imports # sort the python imports
test *TESTS # run tests
test-db DB_CLIENT="dev" *TESTS # test against the specified database backend
test-drf *TESTS # test django rest framework integration
test-extra-views *TESTS # test django extra views integration
test-guardian *TESTS # test guardian integration
test-integrations DB_CLIENT="dev" # run all third party integration tests
test-lock +PACKAGES # lock to specific python and versions of given dependencies
test-reversion *TESTS # test django-revision integration
validate_version VERSION # validate the given version string against the lib version
```
================================================
FILE: LICENSE
================================================
Copyright (c) 2009 or later by the individual contributors.
Please see the AUTHORS file.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
# django-polymorphic
[](https://opensource.org/license/bsd-3-clause)
[](https://github.com/astral-sh/ruff)
[](https://pypi.python.org/pypi/django-polymorphic/)
[](https://pypi.python.org/pypi/django-polymorphic/)
[](https://pypi.org/project/django-polymorphic/)
[](https://pypi.python.org/pypi/django-polymorphic)
[](https://pypi.python.org/pypi/django-polymorphic)
[](http://django-polymorphic.readthedocs.io/?badge=latest/)
[](https://codecov.io/github/django-commons/django-polymorphic?branch=main)
[](https://github.com/django-commons/django-polymorphic/actions/workflows/test.yml?query=branch:main)
[](https://github.com/django-commons/django-polymorphic/actions/workflows/lint.yml?query=branch:main)
[](https://djangopackages.org/packages/p/django-polymorphic/)
[](https://securityscorecards.dev/viewer/?uri=github.com/django-commons/django-polymorphic)
---------------------------------------------------------------------------------------------------
[](https://www.postgresql.org/)
[](https://www.mysql.com/)
[](https://mariadb.org/)
[](https://www.sqlite.org/)
[](https://www.oracle.com/database/)
---------------------------------------------------------------------------------------------------
## Polymorphic Models for Django
[django-polymorphic](https://pypi.python.org/pypi/django-polymorphic) simplifies using inherited models in [Django](https://djangoproject.com) projects. When a query is made at the base model, the inherited model classes are returned.
When we store models that inherit from a ``Project`` model...
```python
>>> Project.objects.create(topic="Department Party")
>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
```
...and want to retrieve all our projects, the subclassed models are returned!
```python
>>> Project.objects.all()
[ <Project: id 1, topic "Department Party">,
<ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
<ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]
```
Using vanilla Django, we get the base class objects, which is rarely what we wanted:
```python
>>> Project.objects.all()
[ <Project: id 1, topic "Department Party">,
<Project: id 2, topic "Painting with Tim">,
<Project: id 3, topic "Swallow Aerodynamics"> ]
```
This also works when the polymorphic model is accessed via
ForeignKeys, ManyToManyFields or OneToOneFields.
### Features
* Full admin integration.
* ORM integration:
* support for ForeignKey, ManyToManyField, OneToOneField descriptors.
* Filtering/ordering of inherited models (``ArtProject___artist``).
* Filtering model types: ``instance_of(...)`` and ``not_instance_of(...)``
* Combining querysets of different models (``qs3 = qs1 | qs2``)
* Support for custom user-defined managers.
* Uses the minimum amount of queries needed to fetch the inherited models.
* Disabling polymorphic behavior when needed.
**Note:** While [django-polymorphic](https://pypi.python.org/pypi/django-polymorphic) makes subclassed models easy to use in Django, we still encourage to use them with caution. Each subclassed model will require Django to perform an ``INNER JOIN`` to fetch the model fields from the database. While taking this in mind, there are valid reasons for using subclassed models. That's what this library is designed for!
For more information, see the [documentation at Read the Docs](https://django-polymorphic.readthedocs.io).
### Installation
```bash
$ pip install django-polymorphic
```
```python
INSTALLED_APPS = [
...
"django.contrib.contenttypes", # we rely on the contenttypes framework
"polymorphic"
]
```
## License
[django-polymorphic](https://pypi.python.org/pypi/django-polymorphic) uses the same license as Django (BSD-like).
================================================
FILE: SECURITY.md
================================================
# Security Policy
[](https://github.com/django-commons/django-polymorphic/actions/workflows/github-code-scanning/codeql?query=branch:main)
[](https://docs.zizmor.sh)
[](https://bandit.readthedocs.io)
[](https://securityscorecards.dev/viewer/?uri=github.com/django-commons/django-polymorphic)
## Supported Versions
Only the latest version [](https://pypi.python.org/pypi/django-polymorphic) is supported.
## Reporting a Vulnerability
If you think you have found a vulnerability, and even if you are not sure, please [report it to us in private](https://github.com/django-commons/django-polymorphic/security/advisories/new). We will review it and get back to you. Please refrain from public discussions of the issue.
================================================
FILE: conftest.py
================================================
import inspect
import subprocess
import sys
import pytest
def pytest_configure(config):
# stash it somewhere global-ish
from polymorphic import tests
tests.HEADLESS = not config.getoption("--headed")
def first_breakable_line(obj) -> tuple[str, int]:
"""
Return the absolute line number of the first executable statement
in a function or bound method.
"""
import ast
import textwrap
func = obj.__func__ if inspect.ismethod(obj) else obj
source = inspect.getsource(func)
source = textwrap.dedent(source)
filename = inspect.getsourcefile(func)
assert filename
_, start_lineno = inspect.getsourcelines(func)
tree = ast.parse(source)
for node in tree.body[0].body:
if (
isinstance(node, ast.Expr)
and isinstance(node.value, ast.Constant)
and isinstance(node.value.value, str)
):
continue
return filename, start_lineno + node.lineno - 1
# fallback: just return the line after the def
return filename, start_lineno + 1
def pytest_runtest_call(item):
# --trace cli option does not work for unittest style tests so we implement it here
test = getattr(item, "obj", None)
if item.config.option.trace and inspect.ismethod(test):
from IPython.terminal.debugger import TerminalPdb
try:
file = inspect.getsourcefile(test)
assert file
dbg = TerminalPdb()
dbg.set_break(*first_breakable_line(test))
dbg.cmdqueue.append("continue")
dbg.set_trace()
except (OSError, AssertionError):
pass
def _install_playwright_browsers() -> None:
cmd = [sys.executable, "-m", "playwright", "install", "chromium"]
subprocess.run(cmd, check=True)
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
any_ui = any(item.get_closest_marker("ui") is not None for item in items)
if any_ui and not getattr(config, "_did_install_playwright", False):
setattr(config, "_did_install_playwright", True)
_install_playwright_browsers()
================================================
FILE: docs/_ext/djangodummy/__init__.py
================================================
================================================
FILE: docs/_ext/djangodummy/requirements.txt
================================================
# for readthedocs
# Remaining requirements are picked up from setup.py
Django>=4.2.20
django-extra-views>=0.14.0
sphinxcontrib-django>=2.5
sphinx_rtd_theme>=2.0.0
================================================
FILE: docs/_ext/djangodummy/settings.py
================================================
# Settings file to allow parsing API documentation of Django modules,
# and provide defaults to use in the documentation.
#
# This file is placed in a subdirectory,
# so the docs root won't be detected by find_packages()
# Display sane URLs in the docs:
STATIC_URL = "/static/"
# Avoid error for missing the secret key
SECRET_KEY = "docs"
INSTALLED_APPS = ["django.contrib.contenttypes"]
================================================
FILE: docs/_static/.gitkeep
================================================
================================================
FILE: docs/_static/style.css
================================================
section#api-documentation div.highlight pre {
color: #b30000;
display: block; /* ensures it's treated as a block */
margin-left: auto; /* auto margins center block elements */
margin-right: auto;
width: fit-content;
}
body[data-theme="light"] section#api-documentation div.highlight,
body[data-theme="light"] section#api-documentation div.highlight pre {
background-color: #f8f8f8;
}
body[data-theme="dark"] section#api-documentation div.highlight,
body[data-theme="dark"] section#api-documentation div.highlight pre {
background-color: #202020;
}
/* AUTO → system prefers DARK (acts like dark unless user forced light) */
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) #api-documentation .highlight,
body:not([data-theme="light"]) #api-documentation .highlight pre {
background-color: #202020;
}
}
/* AUTO → system prefers LIGHT (acts like light unless user forced dark) */
@media (prefers-color-scheme: light) {
body:not([data-theme="dark"]) #api-documentation .highlight,
body:not([data-theme="dark"]) #api-documentation .highlight pre {
background-color: #f8f8f8;
}
}
================================================
FILE: docs/admin.rst
================================================
Admin Integration
=================
Of course, it's possible to register individual polymorphic models in the
:doc:`Django admin interface <django:ref/contrib/admin/index>`. However, to use these models in a
single cohesive interface, some extra base classes are available.
Setup
-----
Both the parent model and child model need to have a :class:`~django.contrib.admin.ModelAdmin`
class.
The shared base model should use the :class:`~polymorphic.admin.PolymorphicParentModelAdmin` as base
class.
* :attr:`~polymorphic.admin.PolymorphicParentModelAdmin.base_model` should be set
* :attr:`~polymorphic.admin.PolymorphicParentModelAdmin.child_models` or
:meth:`~polymorphic.admin.PolymorphicParentModelAdmin.get_child_models` should return an iterable
of Model classes.
The admin class for every child model should inherit from
:class:`~polymorphic.admin.PolymorphicChildModelAdmin`
* :attr:`~polymorphic.admin.PolymorphicChildModelAdmin.base_model` should be set.
Although the child models are registered too, they won't be shown in the admin index page.
This only happens when :attr:`~polymorphic.admin.PolymorphicChildModelAdmin.show_in_index` is set to
``True``.
Fieldset configuration
~~~~~~~~~~~~~~~~~~~~~~
The parent admin is only used for the list display of models, and for the edit/delete view of
non-subclassed models.
All other model types are redirected to the edit/delete/history view of the child model admin.
Hence, the fieldset configuration should be placed on the child admin.
.. tip::
When the child admin is used as base class for various derived classes, avoid using
the standard ``ModelAdmin`` attributes ``form`` and ``fieldsets``.
Instead, use the ``base_form`` and ``base_fieldsets`` attributes.
This allows the :class:`~polymorphic.admin.PolymorphicChildModelAdmin` class
to detect any additional fields in case the child model is overwritten.
.. versionchanged:: 1.0
It's now needed to register the child model classes too.
In :pypi:`django-polymorphic` 0.9 and below, the
:meth:`~polymorphic.admin.PolymorphicParentModelAdmin.child_models` was a tuple of a
(:class:`~django.db.models.Model`, :class:`~polymorphic.admin.PolymorphicChildModelAdmin`). The
admin classes were registered in an internal class, and kept away from the main admin site. This
caused various subtle problems with the :class:`~django.db.models.ManyToManyField` and related
field wrappers, which are fixed by registering the child admin classes too. Note that they are
hidden from the main view, unless
:attr:`~polymorphic.admin.PolymorphicChildModelAdmin.show_in_index` is set.
.. _admin-example:
Example
-------
The models are taken from :ref:`advanced-features`.
.. code-block:: python
from django.contrib import admin
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from .models import ModelA, ModelB, ModelC, StandardModel
class ModelAChildAdmin(PolymorphicChildModelAdmin):
""" Base admin class for all child models """
base_model = ModelA # Optional, explicitly set here.
# By using these `base_...` attributes instead of the regular ModelAdmin `form` and `fieldsets`,
# the additional fields of the child models are automatically added to the admin form.
base_form = ...
base_fieldsets = (
...
)
@admin.register(ModelB)
class ModelBAdmin(ModelAChildAdmin):
base_model = ModelB # Explicitly set here!
# define custom features here
@admin.register(ModelC)
class ModelCAdmin(ModelBAdmin):
base_model = ModelC # Explicitly set here!
show_in_index = True # makes child model admin visible in main admin site
# define custom features here
@admin.register(ModelA)
class ModelAParentAdmin(PolymorphicParentModelAdmin):
""" The parent model admin """
base_model = ModelA # Optional, explicitly set here.
child_models = (ModelB, ModelC)
list_filter = (PolymorphicChildModelFilter,) # This is optional.
Filtering child types
---------------------
Child model types can be filtered by adding a
:class:`~polymorphic.admin.PolymorphicChildModelFilter` to the
:attr:`~django.contrib.admin.ModelAdmin.list_filter` attribute. See the example above.
Inline models
-------------
.. versionadded:: 1.0
Inline models are handled via a special :class:`~polymorphic.admin.StackedPolymorphicInline` class.
For models with a generic foreign key, there is a
:class:`~polymorphic.admin.GenericStackedPolymorphicInline` class available.
When the inline is included to a normal :class:`~django.contrib.admin.ModelAdmin`, make sure the
:class:`~polymorphic.admin.PolymorphicInlineSupportMixin` is included. This is not needed when the
admin inherits from the :class:`~polymorphic.admin.PolymorphicParentModelAdmin` or
:class:`~polymorphic.admin.PolymorphicChildModelAdmin` classes.
In the following example, the ``PaymentInline`` supports several types. These are defined as
separate inline classes. The child classes can be nested for clarity, but this is not a requirement.
.. code-block:: python
from django.contrib import admin
from polymorphic.admin import PolymorphicInlineSupportMixin, StackedPolymorphicInline
from .models import Order, Payment, CreditCardPayment, BankPayment, SepaPayment
class PaymentInline(StackedPolymorphicInline):
"""
An inline for a polymorphic model.
The actual form appearance of each row is determined by
the child inline that corresponds with the actual model type.
"""
class CreditCardPaymentInline(StackedPolymorphicInline.Child):
model = CreditCardPayment
class BankPaymentInline(StackedPolymorphicInline.Child):
model = BankPayment
class SepaPaymentInline(StackedPolymorphicInline.Child):
model = SepaPayment
model = Payment
child_inlines = (
CreditCardPaymentInline,
BankPaymentInline,
SepaPaymentInline,
)
@admin.register(Order)
class OrderAdmin(PolymorphicInlineSupportMixin, admin.ModelAdmin):
"""
Admin for orders.
The inline is polymorphic.
To make sure the inlines are properly handled,
the ``PolymorphicInlineSupportMixin`` is needed to
"""
inlines = (PaymentInline,)
Using polymorphic models in standard inlines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To add a polymorphic child model as an Inline for another model, add a field to the inline's
:attr:`~django.contrib.admin.ModelAdmin.readonly_fields` list formed by the lowercased name of the
polymorphic parent model with the string ``_ptr`` appended to it. Otherwise, trying to save that
model in the admin will raise an :exc:`AttributeError` with the message "can't set attribute".
.. code-block:: python
from django.contrib import admin
from .models import StandardModel
class ModelBInline(admin.StackedInline):
model = ModelB
fk_name = 'modelb'
readonly_fields = ['modela_ptr']
@admin.register(StandardModel)
class StandardModelAdmin(admin.ModelAdmin):
inlines = [ModelBInline]
Internal details
----------------
The polymorphic admin interface works in a simple way:
* The add screen gains an additional step where the desired child model is selected.
* The edit screen displays the admin interface of the child model.
* The list screen still displays all objects of the base class.
The polymorphic admin is implemented via a parent admin that redirects the ``edit`` and ``delete``
views to the :class:`~django.contrib.admin.ModelAdmin` of the derived child model. The ``list`` page
is still implemented by the parent model admin.
The parent model
~~~~~~~~~~~~~~~~
The parent model needs to inherit :class:`~polymorphic.admin.PolymorphicParentModelAdmin`, and
implement the following:
* :attr:`~polymorphic.admin.PolymorphicParentModelAdmin.base_model` should be set
* :attr:`~polymorphic.admin.PolymorphicParentModelAdmin.child_models` or
:meth:`~polymorphic.admin.PolymorphicParentModelAdmin.get_child_models` should return an iterable
of Model classes.
The exact implementation can depend on the way your module is structured. For simple inheritance
situations, :meth:`~polymorphic.admin.PolymorphicParentModelAdmin.child_models` is the best
solution. For large applications,
:meth:`~polymorphic.admin.PolymorphicParentModelAdmin.get_child_models` can be used to query a
plugin registration system.
By default, the :meth:`~polymorphic.managers.PolymorphicQuerySet.non_polymorphic` method will be
called on the queryset, so only the Parent model will be provided to the list template. This is to
avoid the performance hit of retrieving child models.
This can be controlled by setting the
:attr:`~polymorphic.admin.PolymorphicParentModelAdmin.polymorphic_list` property on the parent
admin. Setting it to True will provide child models to the list template.
If you use other applications such as django-reversion_ or django-mptt_, please check
:ref:`integrations`.
Note: If you are using non-integer primary keys in your model, you have to edit
:attr:`~polymorphic.admin.PolymorphicParentModelAdmin.pk_regex`, for example
``pk_regex = '([\w-]+)'`` if you use :class:`~uuid.UUID` primary keys. Otherwise you cannot change
model entries.
The child models
~~~~~~~~~~~~~~~~
The admin interface of the derived models should inherit from
:class:`~polymorphic.admin.PolymorphicChildModelAdmin`. Again,
:attr:`~polymorphic.admin.PolymorphicChildModelAdmin.base_model` should be set in this class as
well. This class implements the following features:
* It corrects the breadcrumbs in the admin pages.
* It extends the template lookup paths, to look for both the parent model and child model in the
``admin/app/model/change_form.html`` path.
* It allows to set :attr:`~polymorphic.admin.PolymorphicChildModelAdmin.base_form` so the derived
class will automatically include other fields in the form.
* It allows to set :attr:`~polymorphic.admin.PolymorphicChildModelAdmin.base_fieldsets` so the
derived class will automatically display any extra fields.
* Although it must be registered with admin site, by default it's hidden from admin site index page.
This can be overridden by adding
:attr:`~polymorphic.admin.PolymorphicChildModelAdmin.show_in_index` = ``True`` in admin class.
.. _django-reversion: https://github.com/etianen/django-reversion
.. _django-mptt: https://github.com/django-mptt/django-mptt
================================================
FILE: docs/advanced.rst
================================================
.. _advanced-features:
Advanced Features
=================
In the examples below, these models are being used:
.. code-block:: python
from django.db import models
from polymorphic.models import PolymorphicModel
class ModelA(PolymorphicModel):
field1 = models.CharField(max_length=10)
class ModelB(ModelA):
field2 = models.CharField(max_length=10)
class ModelC(ModelB):
field3 = models.CharField(max_length=10)
Filtering for classes (equivalent to python's :func:`isinstance`):
------------------------------------------------------------------
.. code-block:: python
>>> ModelA.objects.instance_of(ModelB)
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
In general, including or excluding parts of the inheritance tree:
.. code-block:: python
ModelA.objects.instance_of(ModelB [, ModelC ...])
ModelA.objects.not_instance_of(ModelB [, ModelC ...])
You can also use this feature in Q-objects (with the same result as above):
.. code-block:: python
>>> ModelA.objects.filter( Q(instance_of=ModelB) )
Polymorphic filtering (for fields in inherited classes)
-------------------------------------------------------
For example, cherry-picking objects from multiple derived classes anywhere in the inheritance tree,
using Q objects (with the syntax: ``exact model name + three _ + field name``):
.. code-block:: python
>>> ModelA.objects.filter( Q(ModelB___field2 = 'B2') | Q(ModelC___field3 = 'C3') )
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
Combining Querysets
-------------------
Querysets could now be regarded as object containers that allow the
aggregation of different object types, very similar to python
lists - as long as the objects are accessed through the manager of
a common base class:
.. code-block:: python
>>> Base.objects.instance_of(ModelX) | Base.objects.instance_of(ModelY)
[ <ModelX: id 1, field_x (CharField)>,
<ModelY: id 2, field_y (CharField)> ]
ManyToManyField, ForeignKey, OneToOneField
------------------------------------------
Relationship fields referring to polymorphic models work as
expected: like polymorphic querysets they now always return the
referred objects with the same type/class these were created and
saved as.
E.g., if in your model you define:
.. code-block:: python
field1 = OneToOneField(ModelA)
then field1 may now also refer to objects of type ``ModelB`` or ``ModelC``.
A :class:`~django.db.models.ManyToManyField` example:
.. code-block:: python
# The model holding the relation may be any kind of model, polymorphic or not
class RelatingModel(models.Model):
# ManyToMany relation to a polymorphic model
many2many = models.ManyToManyField('ModelA')
>>> o=RelatingModel.objects.create()
>>> o.many2many.add(ModelA.objects.get(id=1))
>>> o.many2many.add(ModelB.objects.get(id=2))
>>> o.many2many.add(ModelC.objects.get(id=3))
>>> o.many2many.all()
[ <ModelA: id 1, field1 (CharField)>,
<ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
Copying Polymorphic objects
---------------------------
**Copying polymorphic models is no different than copying regular multi-table models.** You have
two options:
1. Use :meth:`~django.db.models.query.QuerySet.create` and provide all field values from the
original instance except the primary key(s).
2. Set the primary key attribute, and parent table pointers at all levels of inheritance to ``None``
and call :meth:`~django.db.models.Model.save`.
The Django documentation :ref:`offers some discussion on copying
<topics/db/queries:copying model instances>`, including the complexity around related fields and
multi-table inheritance. :pypi:`django-polymorphic` offers a utility function
:func:`~polymorphic.utils.prepare_for_copy` that resets all necessary fields on a model instance to
prepare it for copying:
.. code-block:: python
from polymorphic.utils import prepare_for_copy
obj = ModelB.objects.first()
prepare_for_copy(obj)
obj.save()
# obj is now a copy of the original ModelB instance
Working with Fixtures
---------------------
Polymorphic models work with Django's :django-admin:`dumpdata` and :django-admin:`loaddata`
commands just as regular models do. There are two important considerations:
1. Polymorphic models are multi-table models and :django-admin:`dumpdata` serializes each table
separately. :pypi:`django-polymorphic` `does it's best
<https://github.com/django-commons/django-polymorphic/pull/814>`_ to ensure non-polymorphic managers
are used when creating fixtures but there may be edge cases where this fails. If you override
:django-admin:`dumpdata` you must make sure any polymorphic managers encountered
:meth:`toggle polymorphism off <polymorphic.managers.PolymorphicQuerySet.non_polymorphic>`. Other
usual multi-table model caveats apply. If you serialize a subset of tables in the model
inheritance you may generate corrupt data or "upcast" your models if child tables were omitted.
2. Polymorphic models rely on the :class:`~django.contrib.contenttypes.models.ContentType`
framework. When serializing and deserializing polymorphic models, the
``polymorphic_ctype`` field must be handled correctly. If there is any question about if the
content type primary keys are or will be different between the source and target database you
should use the :option:`--natural-foreign <dumpdata.--natural-foreign>` flag to serialize those
relations by-value. Polymorphism introduces no special consideration here - any model using
contenttypes, polymorphic or not, must handle this correctly.
.. note::
Prior documentation urged users to use both :option:`--natural-primary <dumpdata.--natural-primary>`
and :option:`--natural-foreign <dumpdata.--natural-foreign>` flags when dumping polymorphic
models. This is not necessary and only needs to be done when the primary keys are not guaranteed
to match or be available at the target database.
Loading Fixtures (loaddata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fixtures should be loadable as normal with :django-admin:`loaddata`. However, if there are problems
with the ``polymorphic_ctype`` references, you may fix them using
:func:`~polymorphic.utils.reset_polymorphic_ctype`:
.. code-block:: python
from polymorphic.utils import reset_polymorphic_ctype
from myapp.models import Animal, Dog, Cat
# Reset polymorphic_ctype for all models in the inheritance tree
reset_polymorphic_ctype(Animal, Dog, Cat)
Using Third Party Models (without modifying them)
-------------------------------------------------
Third party models can be used as polymorphic models without
restrictions by subclassing them. E.g. using a third party
model as the root of a polymorphic inheritance tree:
.. code-block:: python
from thirdparty import ThirdPartyModel
class MyThirdPartyBaseModel(PolymorphicModel, ThirdPartyModel):
pass # or add fields
Or instead integrating the third party model anywhere into an
existing polymorphic inheritance tree:
.. code-block:: python
class MyBaseModel(SomePolymorphicModel):
my_field = models.CharField(max_length=10)
class MyModelWithThirdParty(MyBaseModel, ThirdPartyModel):
pass # or add fields
Non-Polymorphic Queries
-----------------------
If you insert :meth:`~polymorphic.managers.PolymorphicQuerySet.non_polymorphic` anywhere into the
query chain, then :pypi:`django-polymorphic` will simply leave out the final step of retrieving the
real objects, and the manager/queryset will return objects of the type of the base class you used
for the query, like vanilla Django would (``ModelA`` in this example).
.. code-block:: python
>>> qs=ModelA.objects.non_polymorphic().all()
>>> qs
[ <ModelA: id 1, field1 (CharField)>,
<ModelA: id 2, field1 (CharField)>,
<ModelA: id 3, field1 (CharField)> ]
There are no other changes in the behaviour of the queryset. For example,
enhancements for ``filter()`` or ``instance_of()`` etc. still work as expected.
If you do the final step yourself, you get the usual polymorphic result:
.. code-block:: python
>>> ModelA.objects.get_real_instances(qs)
[ <ModelA: id 1, field1 (CharField)>,
<ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
About Queryset Methods
----------------------
* :meth:`~django.db.models.query.QuerySet.annotate` and
:meth:`~django.db.models.query.QuerySet.aggregate` work just as usual, with the addition that
the ``ModelX___field`` syntax can be used for the keyword arguments (but not for the non-keyword
arguments).
* :meth:`~django.db.models.query.QuerySet.order_by` similarly supports the ``ModelX___field``
syntax for specifying ordering through a field in a submodel.
* :meth:`~django.db.models.query.QuerySet.distinct` works as expected. It only regards the fields
of the base class, but this should never make a difference.
* :meth:`~django.db.models.query.QuerySet.select_related` works just as usual, but it can not
(yet) be used to select relations in inherited models (like
``ModelA.objects.select_related('ModelC___fieldxy')`` )
* :meth:`~django.db.models.query.QuerySet.extra` works as expected (it returns polymorphic
results) but currently has one restriction: The resulting objects are required to have a unique
primary key within the result set - otherwise an error is thrown (this case could be made to
work, however it may be mostly unneeded).. The keyword-argument "polymorphic" is no longer
supported. You can get back the old non-polymorphic behaviour by using
``ModelA.objects.non_polymorphic().extra(...)``.
* :meth:`~polymorphic.managers.PolymorphicQuerySet.get_real_instances` allows you to turn a
queryset or list of base model objects efficiently into the real objects.
For example, you could do ``base_objects_queryset=ModelA.extra(...).non_polymorphic()``
and then call ``real_objects=base_objects_queryset.get_real_instances()``. Or alternatively
``real_objects=ModelA.objects.get_real_instances(base_objects_queryset_or_object_list)``
* :meth:`~django.db.models.query.QuerySet.values` &
:meth:`~django.db.models.query.QuerySet.values_list` currently do not return polymorphic
results. This may change in the future however. If you want to use these methods now, it's best
if you use ``Model.base_objects.values...`` as this is guaranteed to not change.
* :meth:`~django.db.models.query.QuerySet.defer` and :meth:`~django.db.models.query.QuerySet.only`
work as expected. On Django 1.5+ they support the ``ModelX___field`` syntax, but on Django 1.4
it is only possible to pass fields on the base model into these methods.
Using enhanced Q-objects in any Places
--------------------------------------
The queryset enhancements (e.g. :meth:`~polymorphic.managers.PolymorphicQuerySet.instance_of`)
only work as arguments to the member functions of a polymorphic queryset. Occasionally it may
be useful to be able to use Q objects with these enhancements in other places. As Django doesn't
understand these enhanced Q objects, you need to transform them manually into normal Q objects
before you can feed them to a Django queryset or function:
.. code-block:: python
normal_q_object = ModelA.translate_polymorphic_Q_object( Q(instance_of=Model2B) )
This function cannot be used at model creation time however (in models.py), as it may need to access
the ContentTypes database table.
Nicely Displaying Polymorphic Querysets
---------------------------------------
In order to get the output as seen in all examples here, you need to use the
:class:`~polymorphic.showfields.ShowFieldType` class mixin:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.showfields import ShowFieldType
class ModelA(ShowFieldType, PolymorphicModel):
field1 = models.CharField(max_length=10)
You may also use :class:`~polymorphic.showfields.ShowFieldContent` or
:class:`~polymorphic.showfields.ShowFieldTypeAndContent` to display additional information when
printing querysets (or converting them to text).
When showing field contents, they will be truncated to 20 characters. You can modify this behavior
by setting a class variable in your model like this:
.. code-block:: python
class ModelA(ShowFieldType, PolymorphicModel):
polymorphic_showfield_max_field_width = 20
...
Similarly, pre-V1.0 output formatting can be re-estated by using
``polymorphic_showfield_old_format = True``.
Create Children from Parents (Downcasting)
------------------------------------------
You can create an instance of a subclass from an existing instance of a superclass using the
:meth:`~polymorphic.managers.PolymorphicManager.create_from_super` method
of the subclass's manager. For example:
.. code-block:: python
super_instance = ModelA.objects.get(id=1)
sub_instance = ModelB.objects.create_from_super(super_instance, field2='value2')
The restriction is that ``super_instance`` must be an instance of the direct superclass of
``ModelB``, and any required fields of ``ModelB`` must be provided as keyword arguments. If multiple
levels of subclassing are involved, you must call this method multiple times to "promote" each
level.
Delete Children, Leaving Parents (Upcasting)
--------------------------------------------
The reverse operation of :meth:`~polymorphic.managers.PolymorphicManager.create_from_super` is to
delete the subclass instance while keeping the superclass instance. This can be done using the
``keep_parents=True`` argument to :meth:`~django.db.models.Model.delete`. :pypi:`django-polymorphic`
ensures that the ``polymorphic_ctype`` fields of the superclass instances are updated accordingly
when doing this.
.. _restrictions:
Restrictions & Caveats
----------------------
* Database Performance regarding concrete Model inheritance in general. Please see
:ref:`performance`.
* Queryset methods :meth:`~django.db.models.query.QuerySet.values`,
:meth:`~django.db.models.query.QuerySet.values_list`, and
:meth:`~django.db.models.query.QuerySet.select_related` are not yet fully supported (see above).
:meth:`~django.db.models.query.QuerySet.extra` has one restriction: the resulting objects are
required to have a unique primary key within the result set.
* Diamond shaped inheritance: There seems to be a general problem with diamond shaped multiple
model inheritance with Django models (tested with V1.1 - V1.3). An example
`is here <http://code.djangoproject.com/ticket/10808>`_. This problem is aggravated when trying
to enhance :class:`~django.db.models.Model` by subclassing it instead of modifying Django core
(as we do here with :class:`~polymorphic.models.PolymorphicModel`).
* The enhanced filter-definitions/Q-objects only work as arguments for the methods of the
polymorphic querysets. Please see above for ``translate_polymorphic_Q_object``.
* When using the :django-admin:`dumpdata` management command on polymorphic tables
(or any table that has a reference to :class:`~django.contrib.contenttypes.models.ContentType`),
include the :option:`--natural-primary <dumpdata.--natural-primary>` and
:option:`--natural-foreign <dumpdata.--natural-foreign>` flags in the arguments.
* If the ``polymorphic_ctype_id`` on the base table points to the wrong
:class:`~django.contrib.contenttypes.models.ContentType` (this can happen if you delete child
rows manually with raw SQL, ``DELETE FROM table``), then polymorphic queries will elide the
corresponding model objects:
* ``BaseClass.objects.all()`` will **exclude** these rows (it filters for existing child
types).
* ``BaseClass.objects.non_polymorphic().all()`` will behave as normal - but polymorphic
behavior for the affected rows will be undefined - for instance,
:meth:`~polymorphic.managers.PolymorphicQuerySet.get_real_instances` will raise an
exception.
Always use ``instance.delete()`` or ``QuerySet.delete()`` to ensure cascading deletion of the
base row. If you must delete manually, ensure you also delete the corresponding row from the
base table.
* There will be problems if the :class:`~django.contrib.contenttypes.models.ContentType` cache
becomes out of sync with the database. This can especially happen in tests. You should ensure
that the cache is cleared (
:meth:`~django.contrib.contenttypes.models.ContentTypeManager.clear_cache`) whenever this
happens. In tests this happens when if :django-admin:`flush` is called by the teardown sequence
in :class:`~django.test.TransactionTestCase`.
.. old links:
- http://code.djangoproject.com/wiki/ModelInheritance
- http://lazypython.blogspot.com/2009/02/second-look-at-inheritance-and.html
- http://www.djangosnippets.org/snippets/1031/
- http://www.djangosnippets.org/snippets/1034/
- http://groups.google.com/group/django-developers/browse_frm/thread/7d40ad373ebfa912/a20fabc661b7035d?lnk=gst&q=model+inheritance+CORBA#a20fabc661b7035d
- http://groups.google.com/group/django-developers/browse_thread/thread/9bc2aaec0796f4e0/0b92971ffc0aa6f8?lnk=gst&q=inheritance#0b92971ffc0aa6f8
- http://groups.google.com/group/django-developers/browse_thread/thread/3947c594100c4adb/d8c0af3dacad412d?lnk=gst&q=inheritance#d8c0af3dacad412d
- http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/b76c9d8c89a5574f
- http://peterbraden.co.uk/article/django-inheritance
- http://www.hopelessgeek.com/2009/11/25/a-hack-for-multi-table-inheritance-in-django
- http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982
- http://stackoverflow.com/questions/1581024/django-inheritance-how-to-have-one-method-for-all-subclasses
- http://groups.google.com/group/django-users/browse_thread/thread/cbdaf2273781ccab/e676a537d735d9ef?lnk=gst&q=polymorphic#e676a537d735d9ef
- http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/bc18c18b2e83881e?lnk=gst&q=model+inheritance#bc18c18b2e83881e
- http://code.djangoproject.com/ticket/10808
- http://code.djangoproject.com/ticket/7270
================================================
FILE: docs/api/index.rst
================================================
API Documentation
=================
.. _base:
.. automodule:: polymorphic
:members:
:show-inheritance:
:inherited-members:
.. toctree::
polymorphic.admin
polymorphic.contrib/index
polymorphic.formsets
polymorphic.managers
polymorphic.models
polymorphic.deletion
polymorphic.showfields
polymorphic.templatetags/index
polymorphic.utils
================================================
FILE: docs/api/polymorphic.admin.rst
================================================
polymorphic.admin
=================
ModelAdmin classes
------------------
The ``PolymorphicParentModelAdmin`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.PolymorphicParentModelAdmin
:members:
:undoc-members:
:show-inheritance:
The ``PolymorphicChildModelAdmin`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.PolymorphicChildModelAdmin
:members:
:undoc-members:
:show-inheritance:
List filtering
--------------
The ``PolymorphicChildModelFilter`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.PolymorphicChildModelFilter
:show-inheritance:
Inlines support
---------------
The ``StackedPolymorphicInline`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.StackedPolymorphicInline
:show-inheritance:
The ``GenericStackedPolymorphicInline`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.GenericStackedPolymorphicInline
:members:
:undoc-members:
:show-inheritance:
The ``PolymorphicInlineSupportMixin`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: polymorphic.admin.PolymorphicInlineSupportMixin
:members:
:undoc-members:
:show-inheritance:
Low-level classes
-----------------
These classes are useful when existing parts of the admin classes.
.. autoclass:: polymorphic.admin.PolymorphicModelChoiceForm
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: polymorphic.admin.PolymorphicInlineModelAdmin
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: polymorphic.admin.GenericPolymorphicInlineModelAdmin
:members:
:undoc-members:
:show-inheritance:
.. autoclass:: polymorphic.admin.PolymorphicInlineAdminForm
:show-inheritance:
.. autoclass:: polymorphic.admin.PolymorphicInlineAdminFormSet
:show-inheritance:
================================================
FILE: docs/api/polymorphic.contrib/drf.rst
================================================
drf.serializers
===============
.. automodule:: polymorphic.contrib.drf.serializers
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: docs/api/polymorphic.contrib/extra_views.rst
================================================
extra_views
===========
.. automodule:: polymorphic.contrib.extra_views
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: docs/api/polymorphic.contrib/guardian.rst
================================================
guardian
========
.. automodule:: polymorphic.contrib.guardian
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: docs/api/polymorphic.contrib/index.rst
================================================
polymorphic.contrib
===================
.. _contrib:
.. automodule:: polymorphic.contrib
:members:
:show-inheritance:
:inherited-members:
.. toctree::
extra_views
guardian
drf
================================================
FILE: docs/api/polymorphic.deletion.rst
================================================
polymorphic.deletion
====================
.. automodule:: polymorphic.deletion
.. autoclass:: polymorphic.deletion.PolymorphicGuard
:members: __call__
:show-inheritance:
.. autoclass:: polymorphic.deletion.PolymorphicGuardSerializer
:members:
:show-inheritance:
================================================
FILE: docs/api/polymorphic.formsets.rst
================================================
polymorphic.formsets
====================
.. automodule:: polymorphic.formsets
Model formsets
--------------
.. autofunction:: polymorphic.formsets.polymorphic_modelformset_factory
.. autoclass:: polymorphic.formsets.PolymorphicFormSetChild
Inline formsets
---------------
.. autofunction:: polymorphic.formsets.polymorphic_inlineformset_factory
Generic formsets
----------------
.. autofunction:: polymorphic.formsets.generic_polymorphic_inlineformset_factory
Low-level features
------------------
The internal machinery can be used to extend the formset classes. This includes:
.. autofunction:: polymorphic.formsets.polymorphic_child_forms_factory
.. autoclass:: polymorphic.formsets.BasePolymorphicModelFormSet
:show-inheritance:
.. autoclass:: polymorphic.formsets.BasePolymorphicInlineFormSet
:show-inheritance:
.. autoclass:: polymorphic.formsets.BaseGenericPolymorphicInlineFormSet
:show-inheritance:
================================================
FILE: docs/api/polymorphic.managers.rst
================================================
polymorphic.managers
====================
.. automodule:: polymorphic.managers
The ``PolymorphicManager`` class
--------------------------------
.. autoclass:: polymorphic.managers.PolymorphicManager
:members:
:show-inheritance:
The ``PolymorphicQuerySet`` class
---------------------------------
.. autoclass:: polymorphic.managers.PolymorphicQuerySet
:members:
:show-inheritance:
.. _type_hint_descriptors:
Type Hint Descriptors
---------------------
.. autodata:: polymorphic.managers._All
.. autodata:: polymorphic.managers._Base
.. autodata:: polymorphic.managers._Through
.. autodata:: polymorphic.managers._Nullable
.. autodata:: polymorphic.managers.Nullable
.. autoclass:: polymorphic.managers.PolymorphicForwardManyToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicReverseManyToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicForwardOneToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicReverseOneToOneDescriptor
:members:
:show-inheritance:
.. autoclass:: polymorphic.managers.PolymorphicManyToManyDescriptor
:members:
:show-inheritance:
================================================
FILE: docs/api/polymorphic.models.rst
================================================
polymorphic.models
==================
.. automodule:: polymorphic.models
:members:
:show-inheritance:
:private-members:
================================================
FILE: docs/api/polymorphic.showfields.rst
================================================
polymorphic.showfields
======================
.. automodule:: polymorphic.showfields
:members:
:show-inheritance:
:inherited-members:
================================================
FILE: docs/api/polymorphic.templatetags/index.rst
================================================
polymorphic.templatetags
========================
.. _templatetags:
.. automodule:: polymorphic.templatetags
.. toctree::
polymorphic_admin_tags
polymorphic_formset_tags
================================================
FILE: docs/api/polymorphic.templatetags/polymorphic_admin_tags.rst
================================================
polymorphic_admin_tags
======================
.. automodule:: polymorphic.templatetags.polymorphic_admin_tags
:members:
================================================
FILE: docs/api/polymorphic.templatetags/polymorphic_formset_tags.rst
================================================
polymorphic_formset_tags
========================
.. automodule:: polymorphic.templatetags.polymorphic_formset_tags
:members:
================================================
FILE: docs/api/polymorphic.utils.rst
================================================
polymorphic.utils
=================
.. automodule:: polymorphic.utils
:members:
================================================
FILE: docs/changelog/drf.rst
================================================
.. :drf_changelog:
drf
---
Below is the changelog for the :pypi:`django-rest-polymorphic` before it was included into
:pypi:`django-polymorphic`.
0.1.10 (2022-07-17)
+++++++++++++++++++
* Allow partial updates without resourcetype.
0.1.9 (2020-04-02)
++++++++++++++++++
* Fix validation error and update versions.
0.1.8 (2018-10-11)
++++++++++++++++++
* Add Python 3.7 and Django 2.1 support.
0.1.7 (2018-06-06)
++++++++++++++++++
0.1.6 (2018-06-03)
++++++++++++++++++
* Add Django REST Framework 3.8 support.
0.1.5 (2018-03-29)
++++++++++++++++++
* Fix validation for nested serializers.
0.1.4 (2018-02-10)
++++++++++++++++++
* Fix serializer instantiation.
0.1.3 (2018-02-09)
++++++++++++++++++
* Add Python 2.7 support.
0.1.2 (2018-01-30)
++++++++++++++++++
* Add Django 2.0 support.
* Drop Django 1.10 support.
0.1.1 (2017-12-08)
++++++++++++++++++
* Add example project.
0.1.0 (2017-12-07)
++++++++++++++++++
* First release on PyPI.
================================================
FILE: docs/changelog/index.rst
================================================
Changelog
=========
v4.11.3 (2026-04-30)
--------------------
* `django-polymorphic <https://github.com/django-commons/django-polymorphic>`_ has a new home at the
`django-commons <https://django-commons.org>`_ organization!
* This was necessary because `Jazzband is sunsetting
<https://github.com/jazzband/help/issues/425>`_. Jazzband was a great home that facilitated
maintainership transfer of this package. We are extremely thankful for all of `jezdez's
<https://github.com/jezdez>`_ work over the years running the Jazzband community.
* We limited publishing access to restrict our supply chain vulnerability surface. If you were a
former contributor/maintainer of this project and wish to contribute again please `join
django-commons <https://github.com/django-commons/membership>`_ and let us know.
v4.11.2 (2026-03-05)
--------------------
* Add typed classifier.
* Remove unnecessary :func:`~django.utils.safestring.mark_safe` from `admin context variables
<https://github.com/bckohan/django-polymorphic/commit/6c6114d4c72bb6db73eee54ce58beb93409ec137>`_.
* Significant security tightening of CI pipelines including security focused static
analysis tools: zizmor, CodeQL and bandit.
v4.11.1 (2026-02-20)
--------------------
* Fixed `Release 4.11 causes UPDATE query to be routed to reader DB <https://github.com/django-commons/django-polymorphic/issues/865>`_
v4.11.0 (2026-02-05)
--------------------
* Implemented `Add type hints for django-polymorphic <https://github.com/django-commons/django-polymorphic/issues/647>`_
v4.9.2, v4.10.5 (2026-01-26)
----------------------------
* Fixed `Bad warning messages polymorphic.W001 and polymorphic.W002 when deriving from PolymorphicModel <https://github.com/django-commons/django-polymorphic/issues/857>`_
* Fixed `Unexpected return type of polymorphic data since 4.9.1 <https://github.com/django-commons/django-polymorphic/issues/855>`_
* Fixed `related item missing <https://github.com/django-commons/django-polymorphic/issues/851>`_
v4.10.4 (2026-01-19)
--------------------
* Documented `model-bakery integration and test considerations <https://github.com/django-commons/django-polymorphic/issues/849>`_
v4.9.1, v4.10.3 (2026-01-15)
----------------------------
* Fixed `Meta.base_manager_name is not respected <https://github.com/django-commons/django-polymorphic/issues/845>`_
v4.10.2 (2026-01-14)
--------------------
* Fixed `changelog url on pypi is broken <https://github.com/django-commons/django-polymorphic/issues/842>`_
v4.10.1 (2026-01-13)
--------------------
* Fixed `Django-polymorphic does not update the PolymorphicSerializer's validated_data after running the child's validation method <https://github.com/django-commons/django-polymorphic/pull/378>`_
v4.10.0 (2026-01-13)
--------------------
This release is primarily an integrations release. Many tests were added for the documented
intergrations and a few bugs were fixed. Some warnings were converted to system checks. The two most
notable changes are:
1. The :pypi:`django-rest-polymorphic` package is now part of :pypi:`django-polymorphic`.
2. In queries that need content types that are not cached those fetches are `now embedded as
subqueries <https://github.com/django-commons/django-polymorphic/pull/828>`_. This reduces the total
number of queries needed but most importantly it eliminates `a class of errors
<https://github.com/django-commons/django-polymorphic/issues/383>`_ that could happen if
Manager/QuerySet methods that should not but do generate database queries are called before
models are loaded (e.g. get_queryset()).
Issues
~~~~~~
* Implemented `Bring django-rest-polymorphic into this package. <https://github.com/django-commons/django-polymorphic/issues/655>`_
.. tip::
:pypi:`django-rest-polymorphic` is now part of :pypi:`django-polymorphic`. You must update
your import paths from ``rest_polymorphic.serializers`` to
:mod:`polymorphic.contrib.drf.serializers`.
* Fixed `Guardian contenttype integraton hook is extremely brittle <https://github.com/django-commons/django-polymorphic/issues/836>`_
* Fixed `Models defined after load break inheritance utility caches <https://github.com/django-commons/django-polymorphic/issues/827>`_
* Fixed `get_queryset() results in db queries for proxy models <https://github.com/django-commons/django-polymorphic/issues/824>`_
* Implemented `System check error for PolymorphicManager marked as use_in_migrations <https://github.com/django-commons/django-polymorphic/issues/820>`_
* Implemented `Manager warnings should be system checks instead. <https://github.com/django-commons/django-polymorphic/issues/819>`_
v4.9.0 (2026-01-09)
-------------------
.. note::
This update may generate new migrations for your polymorphic models, similar to the following.
This is ok and an expected side effect of fixing `#815
<https://github.com/django-commons/django-polymorphic/issues/815>`_
.. code-block:: python
migrations.AlterModelOptions(
name='modelname',
options={},
)
* Fixed `PolymorphicModel.base_manager is the same as default_manager when custom default manager is supplied. <https://github.com/django-commons/django-polymorphic/issues/815>`_
* Fixed `Use non-polymorphic managers for all invocations of dumpdata <https://github.com/django-commons/django-polymorphic/pull/814>`_
* Documented `Fixture usage <https://github.com/django-commons/django-polymorphic/pull/791>`_
v4.8.0 (2026-01-08)
-------------------
* Fixed `PolymorphicFormSetChild overrides form exclude <https://github.com/django-commons/django-polymorphic/issues/578>`_
* Fixed `Issue with polymorphic_ctype when populating polymorphic inline formsets. <https://github.com/django-commons/django-polymorphic/issues/549>`_
* Fixed `Nested polymorphic_inline_formsets gives AttributeError: 'NoneType' object has no attribute 'get_real_instance_class' <https://github.com/django-commons/django-polymorphic/issues/363>`_
v4.7.0 (2026-01-07)
-------------------
Fixed a few outstanding admin bugs, updated documentation and added more admin tests for things like
m2m relationships.
* Documented `How to handle non-admin polymorphic forms? <https://github.com/django-commons/django-polymorphic/issues/346>`_
* Fixed `Admin: add view popup breaks if initial submit has validation error <https://github.com/django-commons/django-polymorphic/issues/612>`_
* Fixed `Filters are not preserved in polymorphic parent admin <https://github.com/django-commons/django-polymorphic/issues/356>`_
* Fixed `Admin change form doesn't preserve changelist filter <https://github.com/django-commons/django-polymorphic/issues/125>`_
v4.6.0 (2026-01-05)
-------------------
The release fixes longstanding bugs with respect to expected ORM behavior. For a complete list of
changes see the `v4.6.0 release
<https://github.com/django-commons/django-polymorphic/releases/tag/v4.6.0>`_.
* Fixed `get_real_instance() should also gracefully retry parents on failure (best effort) <https://github.com/django-commons/django-polymorphic/issues/784>`_
* Fixed `polymorphic_primary_key_name no longer points to base classes polymorphic field <https://github.com/django-commons/django-polymorphic/issues/758>`_
* Fixed `create_from_super needs to run atomically. <https://github.com/django-commons/django-polymorphic/issues/744>`_
* Fixed `Support polymorphic models that have different pk fields/values at different levels of the hierarchy. <https://github.com/django-commons/django-polymorphic/issues/686>`_
* Fixed `Issue with .delete(keep_parents=True) <https://github.com/django-commons/django-polymorphic/issues/645>`_
* Fixed `PolymorphicChildModelAdmin with show_in_index=False in Django Admin with nav_sidebar <https://github.com/django-commons/django-polymorphic/issues/497>`_
* Fixed `ForeignKeyViolation when trying to save an entity when using a non-default db <https://github.com/django-commons/django-polymorphic/issues/486>`_
* Fixed `Content types pulled from wrong database when using database routers <https://github.com/django-commons/django-polymorphic/issues/446>`_
* Fixed `Copying Polymorphic objects for below the first level not working <https://github.com/django-commons/django-polymorphic/issues/414>`_
* Fixed `Getting a specific element from a queryset in an post_delete returns None <https://github.com/django-commons/django-polymorphic/issues/347>`_
* Fixed `Reverse related object descriptor is overwritten on class <https://github.com/django-commons/django-polymorphic/issues/71>`_
v4.3.1, v4.4.2, v4.5.2 (2026-01-01)
-----------------------------------
* Fixed `Significant performance regression on polymorphic queryset iteration <https://github.com/django-commons/django-polymorphic/pull/781>`_
v4.5.1 (2025-12-24)
-------------------
* Fixed `4.5.0 generates a lot of migrations on my project <https://github.com/django-commons/django-polymorphic/pull/759>`_
* Fixed `Annotations with F <https://github.com/django-commons/django-polymorphic/pull/755>`_
* Fixed `show_in_index=False visibility in admin sites and sidebar <https://github.com/django-commons/django-polymorphic/pull/760>`_
v4.5.0 (2025-12-22)
-------------------
The release fixes longstanding bugs with respect to deletion of polymorphic models.
.. warning::
This version has a bug that generates unnecessary migrations - use 4.5.1 instead!
* Implemented `Deletion fixes <https://github.com/django-commons/django-polymorphic/pull/746>`_
**This release fixes the longstanding polymorphic deletion bug.** The fix should be transparent
and not generate new migrations files. If you experience any issues, please report them.
* Fixed `AttributeError Using .alias() On Polymorphic Querysets <https://github.com/django-commons/django-polymorphic/pull/745>`_
v4.4.1 (2025-12-15)
-------------------
* `Fix infinite recursion bug when using only() <https://github.com/django-commons/django-polymorphic/pull/739>`_
v4.4.0 (2025-12-14)
-------------------
* Implemented `Add create_from_super method and test <https://github.com/django-commons/django-polymorphic/pull/684>`_
* Implemented `Move model definition errors to system checks <https://github.com/django-commons/django-polymorphic/pull/693>`_
* Fixed `Fix ordering of stacked inline admin forms on add. <https://github.com/django-commons/django-polymorphic/pull/719>`_
* Fixed `Change model definition errors to be system checks <https://github.com/django-commons/django-polymorphic/pull/693>`_
* Fixed `Replace deepcopy of the Q object <https://github.com/django-commons/django-polymorphic/pull/543>`_
v4.3.0 (2025-12-09)
-------------------
* Fixed `Resolve primary key name correctly. <https://github.com/django-commons/django-polymorphic/pull/620>`_
* Implemented `Include get_child_inlines() hook in stacked inline admin forms. <https://github.com/django-commons/django-polymorphic/pull/681>`_
* Fixed `multi-database support in inheritance accessors. <https://github.com/django-commons/django-polymorphic/pull/550>`_
* Fixed `Caching in inheritance accessor functions <https://github.com/django-commons/django-polymorphic/pull/510>`_
* Fixed `Foreign key resolves to parent class when using abstract models <https://github.com/django-commons/django-polymorphic/issues/437>`_
* Fixed `Support Q expressions that contain subquery expressions <https://github.com/django-commons/django-polymorphic/pull/572>`_
v4.2.0 (2025-12-04)
-------------------
* Fixed `The objects which were transmogrified aren't initialized correctly if they implement __init__ method. <https://github.com/django-commons/django-polymorphic/issues/615>`_
* Implemented `Defer to chunk_size parameter on .iterators for fetching get_real_instances() <https://github.com/django-commons/django-polymorphic/pull/672>`_
* Fixed `Show full admin context (breadcrumb and logout nav) in model type selection admin form <https://github.com/django-commons/django-polymorphic/pull/580>`_
* Fixed `Issue with Autocomplete Fields in StackedPolymorphicInline.Child Inline <https://github.com/django-commons/django-polymorphic/issues/546>`_
* Support Python 3.14 and Django 6.0, drop support for EOL python 3.9, Django 3.2, 4.0, 4.1 and 5.0.
* `Modernized package management with new build, test, docs tooling and improved CI
<https://github.com/django-commons/django-polymorphic/issues/651>`_.
v4.1.0 (2025-05-20)
-------------------
* `Fixed a bug on Django 5 <https://github.com/django-commons/django-polymorphic/pull/621>`_ where
`aggregation queries could result in None-type errors <https://github.com/django-commons/django-polymorphic/issues/616>`_
* `Use css variables in the admin css <https://github.com/django-commons/django-polymorphic/pull/622>`_
v4.0.0 (2025-05-20)
-------------------
**There were no breaking changes in this major release**
*This was the first release under* `Jazzband <https://jazzband.co/>`_.
There were many updates modernizing the package and incorporating Jazzband standards:
* Updates to documentation
* Formatting and linting with ruff
* Moving to GHA from Travis CI
* Switch to pytest
Changes that touched the core package code were:
* Remove `legacy Django/python version checks <https://github.com/django-commons/django-polymorphic/pull/567>`_
* Replace `string formats with f-strings <https://github.com/django-commons/django-polymorphic/pull/566>`_
* Removed `deprecated usage of package_resources <https://github.com/django-commons/django-polymorphic/pull/541>`_
- as of Python 3.12 package_resources was removed. To get prior releases to work on >3.12 you
would also need to install `setuptools <https://pypi.org/project/setuptools/>`_.
* Fixed `multi field lines do not render in the admin <https://github.com/django-commons/django-polymorphic/pull/539>`_
* Fixed `dark mode rendering in the polymorphic admin <https://github.com/django-commons/django-polymorphic/pull/508>`_
v3.1.0 (2021-11-18)
-------------------
* Added support for Django 4.0.
* Fixed crash when the admin "add type" view has no choices; will show a permission denied.
* Fixed missing ``locale`` folder in sdist.
* Fixed missing ``QuerySet.bulk_create(.., ignore_conflicts=True)`` parameter support.
* Fixed ``FilteredRelation`` support.
* Fixed supporting class keyword arguments in model definitions for ``__init_subclass__()``.
* Fixed including ``polymorphic.tests.migrations`` in the sdist.
* Fixed non-polymorphic parent handling, which has no ``_base_objects``.
* Fixed missing ``widgets`` support for ``modelform_factory()``.
* Fixed ``has_changed`` handling for ``polymorphic_ctype_id`` due to implicit str to int
conversions.
* Fixed ``Q`` object handling when lists are used (e.g. in django-advanced-filters_).
* Fixed Django Admin support when using a script-prefix.
Many thanks to everyone providing clear pull requests!
v3.0.0 (2020-08-21)
-------------------
* Support for Django 3.X
* Dropped support for python 2.X
* A lot of various fixes and improvements by various authors. Thanks a lot!
v2.1.2 (2019-07-15)
-------------------
* Fix ``PolymorphicInlineModelAdmin`` media jQuery include for Django 2.0+
v2.1.1 (2019-07-15)
-------------------
* Fixed admin import error due to ``isort`` changes.
v2.1 (2019-07-15)
-----------------
* Added Django 2.2 support.
* Changed ``.non_polymorphic()``, to use a different iterable class that completely circumvent
polymorphic.
* Changed SQL for ``instance_of`` filter: use ``IN`` statement instead of ``OR`` clauses.
* Changed queryset iteration to implement ``prefetch_related()`` support.
* Fixed Django 3.0 alpha compatibility.
* Fixed compatibility with current django-extra-views_ in ``polymorphic.contrib.extra_views``.
* Fixed ``prefetch_related()`` support on polymorphic M2M relations.
* Fixed model subclass ``___`` selector for abstract/proxy models.
* Fixed model subclass ``___`` selector for models with a custom
``OneToOneField(parent_link=True)``.
* Fixed unwanted results on calling ``queryset.get_real_instances([])``.
* Fixed unwanted ``TypeError`` exception when ``PolymorphicTypeInvalid`` should have raised.
* Fixed hiding the add-button of polymorphic lines in the Django admin.
* Reformatted all files with black
v2.0.3 (2018-08-24)
-------------------
* Fixed admin crash for Django 2.1 with missing ``use_required_attribute``.
v2.0.2 (2018-02-05)
-------------------
* Fixed manager inheritance behavior for Django 1.11, by automatically enabling
``Meta.manager_inheritance_from_future`` if it's not defined. This restores the manager
inheritance behavior that *django-polymorphic 1.3* provided for Django 1.x projects.
* Fixed internal ``base_objects`` usage.
v2.0.1 (2018-02-05)
-------------------
* Fixed manager inheritance detection for Django 1.11.
It's recommended to use ``Meta.manager_inheritance_from_future`` so Django 1.x code also inherit
the ``PolymorphicManager`` in all subclasses. Django 2.0 already does this by default.
* Deprecated the ``base_objects`` manager. Use ``objects.non_polymorphic()`` instead.
* Optimized detection for dumpdata behavior, avoiding the performance hit of ``__getattribute__()``.
* Fixed test management commands
v2.0.0 (2018-01-22)
-------------------
* **BACKWARDS INCOMPATIBILITY:** Dropped Django 1.8 and 1.10 support.
* **BACKWARDS INCOMPATIBILITY:** Removed old deprecated code from 1.0, thus:
* Import managers from ``polymorphic.managers`` (plural), not ``polymorphic.manager``.
* Register child models to the admin as well using ``@admin.register()`` or
``admin.site.register()``, as this is no longer done automatically.
* Added Django 2.0 support.
Also backported into 1.3.1:
* Added ``PolymorphicTypeUndefined`` exception for incomplete imported models.
When a data migration or import creates an polymorphic model,
the ``polymorphic_ctype_id`` field should be filled in manually too.
The ``polymorphic.utils.reset_polymorphic_ctype`` function can be used for that.
* Added ``PolymorphicTypeInvalid`` exception when database was incorrectly imported.
* Added ``polymorphic.utils.get_base_polymorphic_model()`` to find the base model for types.
* Using ``base_model`` on the polymorphic admins is no longer required, as this can be autodetected.
* Fixed manager errors for swappable models.
* Fixed ``deleteText`` of ``|as_script_options`` template filter.
* Fixed ``.filter(applabel__ModelName___field=...)`` lookups.
* Fixed proxy model support in formsets.
* Fixed error with .defer and child models that use the same parent.
* Fixed error message when ``polymorphic_ctype_id`` is null.
* Fixed fieldsets recursion in the admin.
* Improved ``polymorphic.utils.reset_polymorphic_ctype()`` to accept models in random ordering.
* Fix fieldsets handling in the admin (``declared_fieldsets`` is removed since Django 1.9)
v1.3.1 (2018-04-16)
-------------------
Backported various fixes from 2.x to support older Django versions:
* Added ``PolymorphicTypeUndefined`` exception for incomplete imported models.
When a data migration or import creates an polymorphic model,
the ``polymorphic_ctype_id`` field should be filled in manually too.
The ``polymorphic.utils.reset_polymorphic_ctype`` function can be used for that.
* Added ``PolymorphicTypeInvalid`` exception when database was incorrectly imported.
* Added ``polymorphic.utils.get_base_polymorphic_model()`` to find the base model for types.
* Using ``base_model`` on the polymorphic admins is no longer required, as this can be autodetected.
* Fixed manager errors for swappable models.
* Fixed ``deleteText`` of ``|as_script_options`` template filter.
* Fixed ``.filter(applabel__ModelName___field=...)`` lookups.
* Fixed proxy model support in formsets.
* Fixed error with .defer and child models that use the same parent.
* Fixed error message when ``polymorphic_ctype_id`` is null.
* Fixed fieldsets recursion in the admin.
* Improved ``polymorphic.utils.reset_polymorphic_ctype()`` to accept models in random ordering.
* Fix fieldsets handling in the admin (``declared_fieldsets`` is removed since Django 1.9)
v1.3.0 (2017-08-01)
-------------------
* **BACKWARDS INCOMPATIBILITY:** Dropped Django 1.4, 1.5, 1.6, 1.7, 1.9 and Python 2.6 support.
Only official Django releases (1.8, 1.10, 1.11) are supported now.
* Allow expressions to pass unchanged in ``.order_by()``
* Fixed Django 1.11 accessor checks (to support subclasses of ``ForwardManyToOneDescriptor``, like
``ForwardOneToOneDescriptor``)
* Fixed polib syntax error messages in translations.
v1.2.0 (2017-05-01)
-------------------
* Django 1.11 support.
* Fixed ``PolymorphicInlineModelAdmin`` to explictly exclude ``polymorphic_ctype``.
* Fixed Python 3 TypeError in the admin when preserving the query string.
* Fixed Python 3 issue due to ``force_unicode()`` usage instead of ``force_text()``.
* Fixed ``z-index`` attribute for admin menu appearance.
v1.1.0 (2017-02-03)
-------------------
* Added class based formset views in ``polymorphic/contrib/extra_views``.
* Added helper function ``polymorphic.utils.reset_polymorphic_ctype()``.
This eases the migration old existing models to polymorphic.
* Fixed Python 2.6 issue.
* Fixed Django 1.6 support.
v1.0.2 (2016-10-14)
-------------------
* Added helper function for django-guardian_; add
``GUARDIAN_GET_CONTENT_TYPE = 'polymorphic.contrib.guardian.get_polymorphic_base_content_type'``
to the project settings to let guardian handles inherited models properly.
* Fixed ``polymorphic_modelformset_factory()`` usage.
* Fixed Python 3 bug for inline formsets.
* Fixed CSS for Grappelli, so model choice menu properly overlaps.
* Fixed ``ParentAdminNotRegistered`` exception for models that are registered via a proxy model
instead of the real base model.
v1.0.1 (2016-09-11)
-------------------
* Fixed compatibility with manager changes in Django 1.10.1
v1.0.0 (2016-09-02)
-------------------
* Added Django 1.10 support.
* Added **admin inline** support for polymorphic models.
* Added **formset** support for polymorphic models.
* Added support for polymorphic queryset limiting effects on *proxy models*.
* Added support for multiple databases with the ``.using()`` method and ``using=..`` keyword
argument.
* Fixed modifying passed ``Q()`` objects in place.
.. note::
This version provides a new method for registering the admin models.
While the old method is still supported, we recommend to upgrade your code.
The new registration style improves the compatibility in the Django admin.
* Register each ``PolymorphicChildModelAdmin`` with the admin site too.
* The ``child_models`` attribute of the ``PolymorphicParentModelAdmin`` should be a flat list of
all child models. The ``(model, admin)`` tuple is obsolete.
Also note that proxy models will now limit the queryset too.
Fixed since 1.0b1 (2016-08-10)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix formset empty-form display when there are form errors.
* Fix formset empty-form hiding for Grappelli_.
* Fixed packing ``admin/polymorphic/edit_inline/stacked.html`` in the wheel format.
v0.9.2 (2016-05-04)
-------------------
* Fix error when using ``date_hierarchy`` field in the admin
* Fixed Django 1.10 warning in admin add-type view.
v0.9.1 (2016-02-18)
-------------------
* Fixed support for ``PolymorphicManager.from_queryset()`` for custom query sets.
* Fixed Django 1.7 ``changeform_view()`` redirection to the child admin site. This fixes custom
admin code that uses these views, such as django-reversion_'s ``revision_view()`` /
``recover_view()``.
* Fixed ``.only('pk')`` field support.
* Fixed ``object_history_template`` breadcrumb.
**NOTE:** when using django-reversion_ / django-reversion-compare_, make sure to implement
a ``admin/polymorphic/object_history.html`` template in your project that extends
from ``reversion/object_history.html`` or ``reversion-compare/object_history.html`` respectively.
v0.9.0 (2016-02-17)
-------------------
* Added ``.only()`` and ``.defer()`` support.
* Added support for Django 1.8 complex expressions in ``.annotate()`` / ``.aggregate()``.
* Fix Django 1.9 handling of custom URLs.
The new change-URL redirect overlapped any custom URLs defined in the child admin.
* Fix Django 1.9 support in the admin.
* Fix setting an extra custom manager without overriding the ``_default_manager``.
* Fix missing ``history_view()`` redirection to the child admin, which is important for
django-reversion_ support. See the documentation for hints for
`django-reversion-compare support <https://github.com/django-commons/django-polymorphic/discussions/831>_`.
v0.8.1 (2015-12-29)
-------------------
* Fixed support for reverse relations for ``relname___field`` when the field starts with an ``_``
character. Otherwise, the query will be interpreted as subclass lookup (``ClassName___field``).
v0.8.0 (2015-12-28)
-------------------
* Added Django 1.9 compatibility.
* Renamed ``polymorphic.manager`` => ``polymorphic.managers`` for consistentcy.
* **BACKWARDS INCOMPATIBILITY:** The import paths have changed to support Django 1.9.
Instead of ``from polymorphic import X``,
you'll have to import from the proper package. For example:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager, PolymorphicQuerySet
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
* **BACKWARDS INCOMPATIBILITY:** Removed ``__version__.py`` in favor of a standard ``__version__``
in ``polymorphic/__init__.py``.
* **BACKWARDS INCOMPATIBILITY:** Removed automatic proxying of method calls to the queryset class.
Use the standard Django methods instead:
.. code-block:: python
# In model code:
objects = PolymorphicQuerySet.as_manager()
# For manager code:
MyCustomManager = PolymorphicManager.from_queryset(MyCustomQuerySet)
v0.7.2 (2015-10-01)
-------------------
* Added ``queryset.as_manager()`` support for Django 1.7/1.8
* Optimize model access for non-dumpdata usage; avoid ``__getattribute__()`` call each time to
access the manager.
* Fixed 500 error when using invalid PK's in the admin URL, return 404 instead.
* Fixed possible issues when using an custom ``AdminSite`` class for the parent object.
* Fixed Pickle exception when polymorphic model is cached.
v0.7.1 (2015-04-30)
-------------------
* Fixed Django 1.8 support for related field widgets.
v0.7.0 (2015-04-08)
-------------------
* Added Django 1.8 support
* Added support for custom primary key defined using
``mybase_ptr = models.OneToOneField(BaseClass, parent_link=True, related_name="...")``.
* Fixed Python 3 issue in the admin
* Fixed ``_default_manager`` to be consistent with Django, it's now assigned directly instead of
using ``add_to_class()``
* Fixed 500 error for admin URLs without a '/', e.g. ``admin/app/parentmodel/id``.
* Fixed preserved filter for Django admin in delete views
* Removed test noise for diamond inheritance problem (which Django 1.7 detects)
v0.6.1 (2014-12-30)
-------------------
* Remove Django 1.7 warnings
* Fix Django 1.4/1.5 queryset calls on related objects for unknown methods. The ``RelatedManager``
code overrides ``get_query_set()`` while ``__getattr__()`` used the new-style ``get_queryset()``.
* Fix validate_model_fields(), caused errors when metaclass raises errors
v0.6.0 (2014-10-14)
-------------------
* Added Django 1.7 support.
* Added permission check for all child types.
* **BACKWARDS INCOMPATIBILITY:** the ``get_child_type_choices()`` method receives 2 arguments now
(request, action). If you have overwritten this method in your code, make sure the method
signature is updated accordingly.
v0.5.6 (2014-07-21)
-------------------
* Added ``pk_regex`` to the ``PolymorphicParentModelAdmin`` to support non-integer primary keys.
* Fixed passing ``?ct_id=`` to the add view for Django 1.6 (fixes compatibility with
django-parler_).
v0.5.5 (2014-04-29)
-------------------
* Fixed ``get_real_instance_class()`` for proxy models (broke in 0.5.4).
v0.5.4 (2014-04-09)
-------------------
* Fix ``.non_polymorphic()`` to returns a clone of the queryset, instead of effecting the existing
queryset.
* Fix missing ``alters_data = True`` annotations on the overwritten ``save()`` methods.
* Fix infinite recursion bug in the admin with Django 1.6+
* Added detection of bad ``ContentType`` table data.
v0.5.3 (2013-09-17)
-------------------
* Fix TypeError when ``base_form`` was not defined.
* Fix passing ``/admin/app/model/id/XYZ`` urls to the correct admin backend.
There is no need to include a ``?ct_id=..`` field, as the ID already provides enough information.
v0.5.2 (2013-09-05)
-------------------
* Fix Grappelli_ breadcrumb support in the views.
* Fix unwanted ``___`` handling in the ORM when a field name starts with an underscore;
this detects you meant ``relatedfield__ _underscorefield`` instead of ``ClassName___field``.
* Fix missing permission check in the "add type" view. This was caught however in the next step.
* Fix admin validation errors related to additional non-model form fields.
v0.5.1 (2013-07-05)
-------------------
* Add Django 1.6 support.
* Fix Grappelli_ theme support in the "Add type" view.
v0.5.0 (2013-04-20)
-------------------
* Add Python 3.2 and 3.3 support
* Fix errors with ContentType objects that don't refer to an existing model.
v0.4.2 (2013-04-10)
-------------------
* Used proper ``__version__`` marker.
v0.4.1 (2013-04-10)
-------------------
* Add Django 1.5 and 1.6 support
* Add proxy model support
* Add default admin ``list_filter`` for polymorphic model type.
* Fix queryset support of related objects.
* Performed an overall cleanup of the project
* **Deprecated** the ``queryset_class`` argument of the ``PolymorphicManager`` constructor, use the
class attribute instead.
* **Dropped** Django 1.1, 1.2 and 1.3 support
v0.4.0 (2013-03-25)
-------------------
* Update example project for Django 1.4
* Added tox and Travis configuration
v0.3.1 (2013-02-28)
-------------------
* SQL optimization, avoid query in pre_save_polymorphic()
v0.3.0 (2013-02-28)
-------------------
Many changes to the codebase happened, but no new version was released to pypi for years.
0.3 contains fixes submitted by many contributors, huge thanks to everyone!
* Added a polymorphic admin interface.
* PEP8 and code cleanups by various authors
v0.2.0 (2011-04-27)
-------------------
The 0.2 release serves as legacy release.
It supports Django 1.1 up till 1.4 and Python 2.4 up till 2.7.
.. _Grappelli: http://grappelliproject.com/
.. _django-advanced-filters: https://github.com/modlinltd/django-advanced-filters
.. _django-extra-views: https://github.com/AndrewIngram/django-extra-views
.. _django-guardian: https://github.com/django-guardian/django-guardian
.. _django-parler: https://github.com/django-parler/django-parler
.. _django-reversion: https://github.com/etianen/django-reversion
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
V1.0 Release Candidate 1 (2011-01-24)
-------------------------------------
* Fixed GitHub issue 15 (query result incomplete with inheritance).
Thanks to John Debs for reporting and the test case.
Renaming, refactoring, new maintainer (2011-12-20)
--------------------------------------------------
Since the original author disappeared from the internet, we undertook to
maintain and upgrade this piece of software.
The latest "legacy" tag should be V1.0-RC-1. Anything above that should be
considered experimental and unstable until further notice (there be dragons).
New features, bug fixes and other improvements will be added to trunk from now on.
V1.0 Beta 2 (2010-11-11)
------------------------
Beta 2 accumulated somewhat more changes than intended, and also
has been delayed by DBMS benchmark testing I wanted to do on model
inheritance. These benchmarks show that there are considerable
problems with concrete model inheritance and contemporary DBM systems.
The results will be forthcoming on the google discussion forum.
Please also see: http://www.jacobian.org/writing/concrete-inheritance/
The API should be stable now with Beta 2, so it's just about potential
bugfixes from now on regarding V1.0.
Beta 2 is still intended for testing and development environments and not
for production. No complaints have been heard regarding Beta 1 however,
and Beta 1 is used on a few production sites by some enterprising users.
There will be a release candidate for V1.0 in the very near future.
New Features and changes
~~~~~~~~~~~~~~~~~~~~~~~~
* API CHANGE: ``.extra()`` has been re-implemented. Now it's polymorphic by
default and works (nearly) without restrictions (please see docs). This is a (very)
incompatible API change regarding previous versions of django_polymorphic.
Support for the ``polymorphic`` keyword parameter has been removed.
You can get back the non-polymorphic behaviour by using
``ModelA.objects.non_polymorphic().extra(...)``.
* API CHANGE: ``ShowFieldContent`` and ``ShowFieldTypeAndContent`` now
use a slightly different output format. If this causes too much trouble for
your test cases, you can get the old behaviour back (mostly) by adding
``polymorphic_showfield_old_format = True`` to your model definitions.
``ShowField...`` now also produces more informative output for custom
primary keys.
* ``.non_polymorphic()`` queryset member function added. This is preferable to
using ``.base_objects...``, as it just makes the resulting queryset non-polymorphic
and does not change anything else in the behaviour of the manager used (while
``.base_objects`` is just a different manager).
* ``.get_real_instances()``: implementation modified to allow the following
more simple and intuitive use::
>>> qs = ModelA.objects.all().non_polymorphic()
>>> qs.get_real_instances()
which is equivalent to::
>>> ModelA.objects.all()
* added member function:
``normal_q_object = ModelA.translate_polymorphic_Q_object(enhanced_q_object)``
* misc changes/improvements
Bugfixes
~~~~~~~~
* Custom fields could cause problems when used as the primary key.
In inherited models, Django's automatic ".pk" field does not always work
correctly for such custom fields: "some_object.pk" and "some_object.id"
return different results (which they shouldn't, as pk should always be just
an alias for the primary key field). It's unclear yet if the problem lies in
Django or the affected custom fields. Regardless, the problem resulting
from this has been fixed with a small workaround.
"python manage.py test polymorphic" also tests and reports on this problem now.
Thanks to Mathieu Steele for reporting and the test case.
V1.0 Beta 1 (2010-10-18)
------------------------
This release is mostly a cleanup and maintenance release that also
improves a number of minor things and fixes one (non-critical) bug.
Some pending API changes and corrections have been folded into this release
in order to make the upcoming V1.0 API as stable as possible.
This release is also about getting feedback from you in case you don't
approve of any of these changes or would like to get additional
API fixes into V1.0.
The release contains a considerable amount of changes in some of the more
critical parts of the software. It's intended for testing and development
environments and not for production environments. For these, it's best to
wait a few weeks for the proper V1.0 release, to allow some time for any
potential problems to show up (if they exist).
If you encounter any such problems, please post them in the discussion group
or open an issue on GitHub or BitBucket (or send me an email).
There also have been a number of minor API changes.
Please see the README for more information.
New Features
~~~~~~~~~~~~
* official Django 1.3 alpha compatibility
* ``PolymorphicModel.__getattribute__`` hack removed.
This improves performance considerably as python's __getattribute__
generally causes a pretty large processing overhead. It's gone now.
* the ``polymorphic_dumpdata`` management command is not needed anymore
and has been disabled, as the regular Django dumpdata command now automatically
works correctly with polymorphic models (for all supported versions of Django).
* ``.get_real_instances()`` has been elevated to an official part of the API::
real_objects = ModelA.objects.get_real_instances(base_objects_list_or_queryset)
allows you to turn a queryset or list of base objects into a list of the real instances.
This is useful if e.g. you use ``ModelA.base_objects.extra(...)`` and then want to
transform the result to its polymorphic equivalent.
* ``translate_polymorphic_Q_object`` (see DOCS)
* improved testing
* Changelog added: CHANGES.rst/html
Bugfixes
~~~~~~~~
* Removed requirement for primary key to be an IntegerField.
Thanks to Mathieu Steele and Malthe Borch.
API Changes
~~~~~~~~~~~
**polymorphic_dumpdata**
The management command ``polymorphic_dumpdata`` is not needed anymore
and has been disabled, as the regular Django dumpdata command now automatically
works correctly with polymorphic models (for all supported versions of Django).
**Output of Queryset or Object Printing**
In order to improve compatibility with vanilla Django, printing quersets
(__repr__ and __unicode__) does not use django_polymorphic's pretty printing
by default anymore. To get the old behaviour when printing querysets,
you need to replace your model definition:
>>> class Project(PolymorphicModel):
by:
>>> class Project(PolymorphicModel, ShowFieldType):
The mixin classes for pretty output have been renamed:
``ShowFieldTypes, ShowFields, ShowFieldsAndTypes``
are now:
``ShowFieldType, ShowFieldContent and ShowFieldTypeAndContent``
(the old ones still exist for compatibility)
**Running the Test suite with Django 1.3**
Django 1.3 requires ``python manage.py test polymorphic`` instead of
just ``python manage.py test``.
Beta Release (2010-2-22)
------------------------
IMPORTANT: API Changed (import path changed), and Installation Note
The django_polymorphic source code has been restructured
and as a result needs to be installed like a normal Django App
- either via copying the "polymorphic" directory into your
Django project or by running setup.py. Adding 'polymorphic'
to INSTALLED_APPS in settings.py is still optional, however.
The file `polymorphic.py` cannot be used as a standalone
extension module anymore, as is has been split into a number
of smaller files.
Importing works slightly different now: All relevant symbols are
imported directly from 'polymorphic' instead from
'polymorphic.models'::
# new way
from polymorphic import PolymorphicModel, ...
# old way, doesn't work anymore
from polymorphic.models import PolymorphicModel, ...
+ minor API addition: 'from polymorphic import VERSION, get_version'
New Features
~~~~~~~~~~~~
Python 2.4 compatibility, contributed by Charles Leifer. Thanks!
Bugfixes
~~~~~~~~
Fix: The exception "...has no attribute 'sub_and_superclass_dict'"
could be raised. (This occurred if a subclass defined __init__
and accessed class members before calling the superclass __init__).
Thanks to Mattias Brändström.
Fix: There could be name conflicts if
field_name == model_name.lower() or similar.
Now it is possible to give a field the same name as the class
(like with normal Django models).
(Found through the example provided by Mattias Brändström)
Beta Release (2010-2-4)
-----------------------
New features (and documentation)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
queryset order_by method added
queryset aggregate() and extra() methods implemented
queryset annotate() method implemented
queryset values(), values_list(), distinct() documented; defer(),
only() allowed (but not yet supported)
setup.py added. Thanks to Andrew Ingram.
More about these additions in the docs:
``http://bserve.webhop.org/wiki/django_polymorphic/doc``
Bugfixes
~~~~~~~~
* fix remaining potential accessor name clashes (but this only works
with Django 1.2+, for 1.1 no changes). Thanks to Andrew Ingram.
* fix use of 'id' model field, replaced with 'pk'.
* fix select_related bug for objects from derived classes (till now
sel.-r. was just ignored)
"Restrictions & Caveats" updated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Django 1.1 only - the names of polymorphic models must be unique
in the whole project, even if they are in two different apps.
This results from a restriction in the Django 1.1 "related_name"
option (fixed in Django 1.2).
* Django 1.1 only - when ContentType is used in models, Django's
seralisation or fixtures cannot be used. This issue seems to be
resolved for Django 1.2 (changeset 11863: Fixed #7052, Added
support for natural keys in serialization).
Beta Release (2010-1-30)
------------------------
Fixed ContentType related field accessor clash (an error emitted
by model validation) by adding related_name to the ContentType
ForeignKey. This happened if your polymorphc model used a ContentType
ForeignKey. Thanks to Andrew Ingram.
Beta Release (2010-1-29)
------------------------
Restructured django_polymorphic into a regular Django add-on
application. This is needed for the management commands, and
also seems to be a generally good idea for future enhancements
as well (and it makes sure the tests are always included).
The ``poly`` app - until now being used for test purposes only
- has been renamed to ``polymorphic``. See DOCS.rst
("installation/testing") for more info.
Beta Release (2010-1-28)
------------------------
Added the polymorphic_dumpdata management command (github issue 4),
for creating fixtures, this should be used instead of
the normal Django dumpdata command.
Thanks to Charles Leifer.
Important: Using ContentType together with dumpdata generally
needs Django 1.2 (important as any polymorphic model uses
ContentType).
Beta Release (2010-1-26)
------------------------
IMPORTANT - database schema change (more info in change log).
I hope I got this change in early enough before anyone started
to use polymorphic.py in earnest. Sorry for any inconvenience.
This should be the final DB schema now.
Django's ContentType is now used instead of app-label and model-name
This is a cleaner and more efficient solution
Thanks to Ilya Semenov for the suggestion.
.. toctree::
drf
================================================
FILE: docs/conf.py
================================================
#
# django-polymorphic documentation build configuration file, created by
# sphinx-quickstart on Sun May 19 12:20:47 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
import shutil
import sys
from pathlib import Path
import django
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath("_ext"))
sys.path.insert(0, os.path.abspath(".."))
os.environ["DJANGO_SETTINGS_MODULE"] = "polymorphic.tests.settings"
django.setup()
import polymorphic # noqa: E402
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.graphviz",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinxcontrib_django",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
# -- Project information -----------------------------------------------------
project = polymorphic.__title__
copyright = polymorphic.__copyright__
author = polymorphic.__author__
release = polymorphic.__version__
version = ".".join(polymorphic.__version__.split(".")[:2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
# pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "furo"
html_theme_options = {
"source_repository": "https://github.com/jazzband/django-polymorphic/",
"source_branch": "main",
"source_directory": "docs",
}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = [
"style.css",
]
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = "django-polymorphicdoc"
# -- Options for LaTeX output --------------------------------------------------
latex_engine = "xelatex"
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
(
"index",
"django-polymorphic.tex",
"django-polymorphic Documentation",
"Bert Constantin, Chris Glass, Diederik van der Boor, Brian Kohan",
"manual",
)
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(
"index",
"django-polymorphic",
"django-polymorphic Documentation",
["Bert Constantin, Chris Glass, Diederik van der Boor", "Brian Kohan"],
1,
)
]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
"index",
"django-polymorphic",
"django-polymorphic Documentation",
"Bert Constantin, Chris Glass, Diederik van der Boor, Brian Kohan",
"django-polymorphic",
"One line description of project.",
"Miscellaneous",
)
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
intersphinx_mapping = {
"django": (
"https://docs.djangoproject.com/en/stable",
"https://docs.djangoproject.com/en/stable/_objects/",
),
"python": ("https://docs.python.org/3", None),
"typing-extensions": ("https://typing-extensions.readthedocs.io/en/latest/", None),
"django-guardian": ("https://django-guardian.readthedocs.io/en/stable", None),
"django-reversion": ("https://django-reversion.readthedocs.io/en/stable", None),
"django-extra-views": ("https://django-extra-views.readthedocs.io/en/stable", None),
"model-bakery": ("https://model-bakery.readthedocs.io/en/stable", None),
}
# autodoc settings
autodoc_default_options = {
"show-inheritance": True,
# Add other autodoc options here if desired, e.g.:
# 'members': True,
# 'inherited-members': True,
}
# In your Sphinx conf.py
autodoc_typehints = "description"
autodoc_typehints_format = "short"
autodoc_class_signature = "separated"
autodoc_member_order = "groupwise" # "bysource"
# sphinxcontrib-django / Sphinx 9+ autodoc compat
autodoc_use_legacy_class_based = True
def pypi_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
from docutils import nodes
url = f"https://pypi.org/project/{text}/"
node = nodes.reference(rawtext, text, refuri=url, **options)
return [node], []
def setup(app):
from docutils.parsers.rst import roles
# https://sphinxcontrib-typer.readthedocs.io/en/latest/howto.html#build-to-multiple-formats
if Path(app.doctreedir).exists():
shutil.rmtree(app.doctreedir)
app.add_crossref_type(directivename="django-admin", rolename="django-admin")
roles.register_local_role("pypi", pypi_role)
return app
================================================
FILE: docs/deletion.rst
================================================
Deletion
========
.. versionadded:: 4.5.0
There is nothing special about deleting polymorphic models. The same rules apply as to
:ref:`the deletion of normal Django models <topics-db-queries-delete>` that have parent/child
relationships up and down a model inheritance hierarchy. Django must walk the model inheritance and
relationship graph and collect all of the affected objects so that it can correctly order deletion
SQL statements to respect database constraints and issue signals.
The polymorphic deletion logic is the same as the normal Django deletion logic because Django
already walks the model inheritance hierarchy. :class:`~polymorphic.query.PolymorphicQuerySet` and
:class:`~polymorphic.managers.PolymorphicManager` disrupt this process by confusing Django's graph
walker by returning concrete subclass instances instead of base class instances when it attempts to
walk reverse relationships to polymorphic models. To prevent this confusion,
:pypi:`django-polymorphic` wraps the :attr:`~django.db.models.ForeignKey.on_delete` handlers of
reverse relations to polymorphic models with :class:`~polymorphic.deletion.PolymorphicGuard`
which disables polymorphic behavior on the related querysets during collection.
**You may define your polymorphic models as you normally would using the standard Django**
:attr:`~django.db.models.ForeignKey.on_delete` **actions**.
:class:`~polymorphic.models.PolymorphicModel` will automatically wrap the actions for you. actions
wrapped with :class:`~polymorphic.deletion.PolymorphicGuard` serialize in migrations as the
underlying wrapped action. This ensures migrations generated by versions of
:pypi:`django-polymorphic` after 4.5.0 should be the same as with prior versions. The guard is also
unnecessary during migrations because Django generates basic managers instead of using the default
polymorphic managers.
It is a design goal of :pypi:`django-polymorphic` that deletion should just work without any special
treatment. However if you encounter attribute errors or database integrity errors during deletion
you may manually wrap the :attr:`~django.db.models.ForeignKey.on_delete` action of reverse relations
to polymorphic models with :class:`~polymorphic.deletion.PolymorphicGuard` to disable polymorphic
behavior during deletion collection. If you encounter an issue like this
`please report it to us <https://github.com/django-commons/django-polymorphic/issues>`_. For example:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.deletion import PolymorphicGuard
from django.db import models
class MyModel(models.Model):
# ...
class RelatedModel(PolymorphicModel):
my_model = models.ForeignKey(
MyModel,
on_delete=PolymorphicGuard(models.CASCADE),
)
Deleting Children (upcasting)
-----------------------------
When deleting a polymorphic model instance, you can choose to keep the parent model instances by
passing the ``keep_parents=True`` argument to the
:meth:`~polymorphic.models.PolymorphicModel.delete` method. This will delete only the subclass
instance, and leave the parent instances intact. :pypi:`django-polymorphic` will ensure that the
``polymorphic_ctype`` fields of the parent instances are updated accordingly to reflect their new
concrete model type.
.. tip::
You can delete multiple levels of child rows by deleting the model from the desired parent
level. For example, if you have a model inheritance hierarchy of ``Base -> ChildA -> ChildB``,
and you delete a ``ChildB`` row from its parent model ``ChildA`` instance both the ``ChildA``
and ``ChildB`` rows will be deleted leaving a concrete row type of ``Base``.
================================================
FILE: docs/formsets.rst
================================================
Formsets
========
.. versionadded:: 1.0
Polymorphic models can be used in formsets.
The implementation is almost identical to the regular Django :doc:`django:topics/forms/formsets`.
As extra parameter, the factory needs to know how to display the child models.
Provide a list of :class:`~polymorphic.formsets.PolymorphicFormSetChild` objects for this.
.. code-block:: python
from polymorphic.formsets import polymorphic_modelformset_factory, PolymorphicFormSetChild
ModelAFormSet = polymorphic_modelformset_factory(ModelA, formset_children=(
PolymorphicFormSetChild(ModelB),
PolymorphicFormSetChild(ModelC),
))
The formset can be used just like all other formsets:
.. code-block:: python
if request.method == "POST":
formset = ModelAFormSet(request.POST, request.FILES, queryset=ModelA.objects.all())
if formset.is_valid():
formset.save()
else:
formset = ModelAFormSet(queryset=ModelA.objects.all())
Like standard Django :doc:`django:topics/forms/formsets`, there are 3 factory methods available:
* :func:`~polymorphic.formsets.polymorphic_modelformset_factory` - create a regular model formset.
* :func:`~polymorphic.formsets.polymorphic_inlineformset_factory` - create a inline model formset.
* :func:`~polymorphic.formsets.generic_polymorphic_inlineformset_factory` - create an inline formset
for a generic foreign key.
Each one uses a different base class:
* :class:`~polymorphic.formsets.BasePolymorphicModelFormSet`
* :class:`~polymorphic.formsets.BasePolymorphicInlineFormSet`
* :class:`~polymorphic.formsets.BaseGenericPolymorphicInlineFormSet`
When needed, the base class can be overwritten and provided to the factory via the ``formset``
parameter.
================================================
FILE: docs/index.rst
================================================
django-polymorphic
==================
.. only:: html
.. image:: https://img.shields.io/badge/License-BSD-blue.svg
:target: https://opensource.org/license/bsd-3-clause
:alt: License: BSD
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff
:alt: Ruff
.. image:: https://badge.fury.io/py/django-polymorphic.svg
:target: https://pypi.python.org/pypi/django-polymorphic/
:alt: PyPI version
.. image:: https://img.shields.io/pypi/pyversions/django-polymorphic.svg
:target: https://pypi.python.org/pypi/django-polymorphic/
:alt: PyPI pyversions
.. image:: https://img.shields.io/pypi/djversions/django-polymorphic.svg
:target: https://pypi.org/project/django-polymorphic/
:alt: PyPI Django versions
.. image:: https://img.shields.io/pypi/status/django-polymorphic.svg
:target: https://pypi.python.org/pypi/django-polymorphic
:alt: PyPI status
.. image:: https://img.shields.io/pypi/types/django-polymorphic.svg
:target: https://pypi.python.org/pypi/django-polymorphic
:alt: PyPi Typed
.. image:: https://readthedocs.org/projects/django-polymorphic/badge/?version=latest
:target: http://django-polymorphic.readthedocs.io/?badge=latest/
:alt: Documentation Status
.. image:: https://img.shields.io/codecov/c/github/django-commons/django-polymorphic/main.svg
:target: https://codecov.io/github/django-commons/django-polymorphic?branch=main
:alt: Code Coverage
.. image:: https://github.com/django-commons/django-polymorphic/actions/workflows/test.yml/badge.svg?branch=main
:target: https://github.com/django-commons/django-polymorphic/actions/workflows/test.yml?query=branch:main
:alt: Test Status
.. image:: https://github.com/django-commons/django-polymorphic/actions/workflows/lint.yml/badge.svg?branch=main
:target: https://github.com/django-commons/django-polymorphic/actions/workflows/lint.yml?query=branch:main
:alt: Lint Status
.. image:: https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26
:target: https://djangopackages.org/packages/p/django-polymorphic/
:alt: Published on Django Packages
:pypi:`django-polymorphic` builds on top of the standard Django model inheritance.
It makes using inherited models easier. When a query is made at the base model,
the inherited model classes are returned.
When we store models that inherit from a ``Project`` model...
.. code-block:: python
>>> Project.objects.create(topic="Department Party")
>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
...and want to retrieve all our projects, the subclassed models are returned!
.. code-block:: python
>>> Project.objects.all()
[ <Project: id 1, topic "Department Party">,
<ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
<ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]
Using vanilla Django, we get the base class objects, which is rarely what we wanted:
.. code-block:: python
>>> Project.objects.all()
[ <Project: id 1, topic "Department Party">,
<Project: id 2, topic "Painting with Tim">,
<Project: id 3, topic "Swallow Aerodynamics"> ]
Features
--------
* Full admin integration.
* ORM integration:
- Support for ForeignKey, ManyToManyField, OneToOneField descriptors.
- Support for proxy models.
- Filtering/ordering of inherited models (``ArtProject___artist``).
- Filtering model types: :meth:`~polymorphic.managers.PolymorphicQuerySet.instance_of` and
:meth:`~polymorphic.managers.PolymorphicQuerySet.not_instance_of`
- Combining querysets of different models (``qs3 = qs1 | qs2``)
- Support for custom user-defined managers.
* Formset support.
* Uses the minimum amount of queries needed to fetch the inherited models.
* Disabling polymorphic behavior when needed.
Getting started
---------------
.. toctree::
:maxdepth: 2
quickstart
admin
performance
integrations/index
Advanced topics
---------------
.. toctree::
:maxdepth: 2
formsets
views
migrating
managers
deletion
typing
advanced
changelog/index
api/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
================================================
FILE: docs/integrations/drf.rst
================================================
.. _django-rest-framework-support:
===================
djangorestframework
===================
Polymorphic serializers for `Django REST Framework <https://www.django-rest-framework.org/>`_.
The :pypi:`django-rest-polymorphic` package has been incorporated into :pypi:`django-polymorphic`.
This contrib package allows you to easily define serializers for your inherited models that you have
created using ``django-polymorphic`` library. To migrate from :pypi:`django-rest-polymorphic`, you
need to change your import paths from ``rest_polymorphic.serializers`` to
``polymorphic.contrib.drf.serializers``.
Usage
-----
Define your polymorphic models:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/drf/models/example_models.py
:language: python
:linenos:
Define serializers for each polymorphic model the way you did it when you used
:pypi:`djangorestframework`:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/drf/example_serializers.py
:language: python
:linenos:
:lines: 1-29
Note that if you extend `HyperlinkedModelSerializer
<https://www.django-rest-framework.org/api-guide/serializers/#hyperlinkedmodelserializer>`_ instead
of `ModelSerializer <https://www.django-rest-framework.org/api-guide/serializers/#modelserializer>`_
you need to define `extra_kwargs
<https://www.django-rest-framework.org/community/3.0-announcement/#the-extra_kwargs-option>`_ to
direct the URL to the appropriate view for your polymorphic serializer.
Then you have to create a polymorphic serializer that serves as a mapper between models and
serializers which you have defined above:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/drf/example_serializers.py
:language: python
:lines: 32-
Create viewset with serializer_class equals to your polymorphic serializer:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/drf/views.py
:language: python
:linenos:
Test it:
.. code-block:: bash
$ http GET "http://localhost:8000/projects/"
.. code-block:: http
HTTP/1.0 200 OK
Content-Length: 227
Content-Type: application/json
[
{
"resourcetype": "Project",
"topic": "John's gathering"
},
{
"artist": "T. Turner",
"resourcetype": "ArtProject",
"topic": "Sculpting with Tim",
"url": "http://localhost:8000/projects/2/"
},
{
"resourcetype": "ResearchProject",
"supervisor": "Dr. Winter",
"topic": "Swallow Aerodynamics"
}
]
.. code-block:: bash
$ http POST "http://localhost:8000/projects/" resourcetype="ArtProject" topic="Guernica" artist="Picasso"
.. code-block:: http
HTTP/1.0 201 Created
Content-Length: 67
Content-Type: application/json
{
"artist": "Picasso",
"resourcetype": "ArtProject",
"topic": "Guernica",
"url": "http://localhost:8000/projects/4/"
}
Customize resource type
-----------------------
As you can see from the example above, in order to specify the type of your polymorphic model, you
need to send a request with resource type field. The value of resource type should be the name of
the model.
If you want to change the resource type field name from ``resourcetype`` to something else, you
should override ``resource_type_field_name`` attribute:
.. code-block:: python
class ProjectPolymorphicSerializer(PolymorphicSerializer):
resource_type_field_name = 'projecttype'
...
If you want to change the behavior of resource type, you should override ``to_resource_type``
method:
.. code-block:: python
class ProjectPolymorphicSerializer(PolymorphicSerializer):
...
def to_resource_type(self, model_or_instance):
return model_or_instance._meta.object_name.lower()
Now, the request for creating new object will look like this:
.. code-block:: bash
$ http POST "http://localhost:8000/projects/" projecttype="artproject" topic="Guernica" artist="Picasso"
================================================
FILE: docs/integrations/index.rst
================================================
.. _integrations:
Integrations
============
When integrating polymorphic models into third party apps you have three primary options:
0. Hope it just works (it might!).
1. Ensure the querysets the third party apps see are
:meth:`not polymorphic <polymorphic.query.PolymorphicQuerySet.non_polymorphic>`.
2. Override or extend relevant third party app code to work with polymorphic querysets.
If it does not just work, option 1 is usually the easiest. We provide some integrations in
:mod:`polymorphic.contrib` for popular third party apps and provide guidance for others below.
This page does not exhaustively cover all integrations. If you feel your integration need is
very common you may consider opening a PR to either provide support in code or documentation here.
This page covers supported and tested integration advice. For all other integration advice please
refer to `our integrations discussion page
<https://github.com/jazzband/django-polymorphic/discussions/categories/integrations>`_.
For the integration examples on this page, we use the following polymorphic model hierarchy:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/models.py
:language: python
:linenos:
.. _django-django-guardian-support:
:pypi:`django-guardian`
-----------------------
.. versionadded:: 1.0.2
No special modifications are required to integrate with :pypi:`django-guardian`. However, if you
would like all object level permissions to be managed at the base model level, rather than have
unique permissions for each polymorphic subclass, then you can use the helper function
:func:`polymorphic.contrib.guardian.get_polymorphic_base_content_type` to unify the permissions
for your entire polymorphic model tree into a single namespace a the base level:
.. code-block:: python
GUARDIAN_GET_CONTENT_TYPE = \
"polymorphic.contrib.guardian.get_polymorphic_base_content_type"
This option requires :pypi:`django-guardian` >= 1.4.6. Details about how this option works are
available in the `django-guardian documentation
<https://django-guardian.readthedocs.io/en/stable/configuration>`_.
.. _django-extra-views-support:
:pypi:`django-extra-views`
--------------------------
.. versionadded:: 1.1
The :mod:`polymorphic.contrib.extra_views` package provides classes to display polymorphic formsets
using the classes from :pypi:`django-extra-views`. See the documentation of:
* :class:`~polymorphic.contrib.extra_views.PolymorphicFormSetView`
* :class:`~polymorphic.contrib.extra_views.PolymorphicInlineFormSetView`
* :class:`~polymorphic.contrib.extra_views.PolymorphicInlineFormSet`
.. tip::
The complete working code for this example can be found `in the extra_views integration test
<https://github.com/jazzband/django-polymorphic/tree/HEAD/src/polymorphic/tests/examples/integrations/extra_views>`_.
Example View
~~~~~~~~~~~~
Here's how to create a view using :class:`~polymorphic.contrib.extra_views.PolymorphicFormSetView`
to handle polymorphic formsets:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/extra_views/views.py
:language: python
:linenos:
URL Configuration
~~~~~~~~~~~~~~~~~
Configure the URL patterns to route to your formset view:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/extra_views/urls.py
:language: python
:linenos:
Template
~~~~~~~~
The template for rendering the formset:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/extra_views/templates/extra_views/article_formset.html
:language: html+django
``model_name`` is a template tag implemented like so:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/extra_views/templatetags/extra_views_tags.py
:language: python
:lines: 6-
.. _django-reversion-support:
:pypi:`django-reversion`
------------------------
Support for :pypi:`django-reversion` works as expected with polymorphic models. We just need to
do two things:
1. Inherit our admin classes from both :class:`~polymorphic.admin.PolymorphicParentModelAdmin` /
:class:`~polymorphic.admin.PolymorphicChildModelAdmin` and
:ref:`VersionAdmin <django-reversion:versionadmin>`.
2. Override the ``admin/polymorphic/object_history.html`` template.
.. tip::
The complete working code for this example can be found `in the reversion integration test
<https://github.com/jazzband/django-polymorphic/tree/HEAD/src/polymorphic/tests/examples/integrations/reversion>`_.
Admin Configuration
~~~~~~~~~~~~~~~~~~~
The admin configuration combines :class:`~polymorphic.admin.PolymorphicParentModelAdmin` and
:class:`~polymorphic.admin.PolymorphicChildModelAdmin` with
:ref:`VersionAdmin <django-reversion:versionadmin>`:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/reversion/admin.py
:language: python
:linenos:
Custom Template
~~~~~~~~~~~~~~~
Since both :class:`~polymorphic.admin.PolymorphicParentModelAdmin` and
:ref:`VersionAdmin <django-reversion:versionadmin>`. define ``object_history.html`` template, you
need to create a custom template that combines both:
.. literalinclude:: ../../src/polymorphic/tests/examples/integrations/reversion/templates/admin/polymorphic/object_history.html
:language: html+django
This makes sure both the reversion template is used, and the breadcrumb is corrected for the
polymorphic model using the :templatetag:`breadcrumb_scope`
tag.
.. _model-bakery:
:pypi:`model-bakery`
--------------------
:pypi:`model-bakery` does not work without without special configuration for polymorphic models
because it overrides the :attr:`~polymorphic.models.PolymorphicModel.polymorphic_ctype` field.
The best option to make it work in all cases is to `supply a custom Baker
<https://model-bakery.readthedocs.io/en/latest/how_bakery_behaves.html#customizing-baker>`_ class
that fills in all fields except :attr:`~polymorphic.models.PolymorphicModel.polymorphic_ctype`:
.. code-block:: python
:linenos:
:caption: yoursite/tests/baker.py
from polymorphic.models import PolymorphicModel
from model_bakery import baker
class PolymorphicAwareBaker(baker.Baker):
"""
Our custom model baker ignores the polymorphic_ctype field on all polymorphic
models - this allows the base class to set it correctly.
See https://github.com/python/pythondotorg/issues/2567
"""
def get_fields(self):
fields = super().get_fields()
if issubclass(self.model, PolymorphicModel):
fields = {
field
for field in fields
if field.name != "polymorphic_ctype"
}
return fields
Then in your test settings file:
.. code-block:: python
BAKER_CUSTOM_CLASS = "yoursite.tests.baker.PolymorphicAwareBaker"
You may also simply pass the correct :class:`~django.contrib.contenttypes.models.ContentType`
instance to the :attr:`~polymorphic.models.PolymorphicModel.polymorphic_ctype` field when creating
polymorphic model instances with ``make()``
Other Integrations
------------------
.. toctree::
:maxdepth: 1
:titlesonly:
drf
================================================
FILE: docs/managers.rst
================================================
Managers & Querysets
====================
Using a Custom Manager
----------------------
A nice feature of Django is the possibility to define one's own custom object managers.
This is fully supported with :pypi:`django-polymorphic`. For creating a custom polymorphic
manager class, just derive your manager from :class:`~polymorphic.managers.PolymorphicManager`
instead of :class:`~django.db.models.Manager`. As with vanilla Django, in your model class, you
should explicitly add the default manager first, and then your custom manager:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
class TimeOrderedManager(PolymorphicManager):
def get_queryset(self):
qs = super(TimeOrderedManager,self).get_queryset()
return qs.order_by('-start_date')
def most_recent(self):
qs = self.get_queryset() # get my ordered queryset
return qs[:10] # limit => get ten most recent entries
class Project(PolymorphicModel):
objects = PolymorphicManager() # add the default polymorphic manager first
objects_ordered = TimeOrderedManager() # then add your own manager
start_date = DateTimeField() # project start is this date/time
The first manager defined (:attr:`~django.db.models.Model.objects` in the example) is used by Django
as automatic manager for several purposes, including accessing related objects. It must not filter
objects and it's safest to use the plain :class:`~polymorphic.managers.PolymorphicManager` here.
Manager Inheritance
-------------------
Polymorphic models inherit/propagate all managers from their base models, as long as these are
polymorphic. This means that all managers defined in polymorphic base models continue to work as
expected in models inheriting from this base model:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
class TimeOrderedManager(PolymorphicManager):
def get_queryset(self):
qs = super(TimeOrderedManager,self).get_queryset()
return qs.order_by('-start_date')
def most_recent(self):
qs = self.get_queryset() # get my ordered queryset
return qs[:10] # limit => get ten most recent entries
class Project(PolymorphicModel):
objects = PolymorphicManager() # add the default polymorphic manager first
objects_ordered = TimeOrderedManager() # then add your own manager
start_date = DateTimeField() # project start is this date/time
class ArtProject(Project): # inherit from Project, inheriting its fields and managers
artist = models.CharField(max_length=30)
ArtProject inherited the managers ``objects`` and ``objects_ordered`` from Project.
``ArtProject.objects_ordered.all()`` will return all art projects ordered regarding their start time
and ``ArtProject.objects_ordered.most_recent()`` will return the ten most recent art projects.
Using a Custom Queryset Class
-----------------------------
The :class:`~polymorphic.managers.PolymorphicManager` class accepts one initialization argument,
which is the queryset class the manager should use. Just as with vanilla Django, you may define your
own custom queryset classes. Just use :class:`~polymorphic.managers.PolymorphicQuerySet` instead of
Django's :class:`~django.db.models.query.QuerySet` as the base class:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
from polymorphic.query import PolymorphicQuerySet
class MyQuerySet(PolymorphicQuerySet):
def my_queryset_method(self):
...
class MyModel(PolymorphicModel):
my_objects = PolymorphicManager.from_queryset(MyQuerySet)()
...
If you do not wish to extend from a custom :class:`~polymorphic.managers.PolymorphicManager` you
may also prefer the :meth:`~polymorphic.managers.PolymorphicQuerySet.as_manager`
shortcut:
.. code-block:: python
from polymorphic.models import PolymorphicModel
from polymorphic.query import PolymorphicQuerySet
class MyQuerySet(PolymorphicQuerySet):
def my_queryset_method(self):
...
class MyModel(PolymorphicModel):
my_objects = MyQuerySet.as_manager()
...
For further discussion see `this topic on the Q&A page
<https://github.com/django-commons/django-polymorphic/discussions/696#discussioncomment-15223661>`_.
================================================
FILE: docs/migrating.rst
================================================
Migrating Existing Models
=========================
Existing models can be migrated to become polymorphic models. During migration, the
:attr:`~polymorphic.models.PolymorphicModel.polymorphic_ctype` field needs to be populated.
This can be done in the following steps:
#. Inherit your model from :class:`~polymorphic.models.PolymorphicModel`.
#. Create a Django migration file to create the ``polymorphic_ctype_id`` database column.
#. Make sure the proper :class:`~django.contrib.contenttypes.models.ContentType` value is filled in.
Filling the content type value
------------------------------
The following code can be used to fill the value of a model:
.. code-block:: python
from django.contrib.contenttypes.models import ContentType
from myapp.models import MyModel
new_ct = ContentType.objects.get_for_model(MyModel)
MyModel.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=new_ct)
The creation and update of the ``polymorphic_ctype_id`` column can be included in a single Django
migration. For example:
.. code-block:: python
# -*- coding: utf-8 -*-
from django.db import migrations, models
def forwards_func(apps, schema_editor):
MyModel = ap
gitextract_t9wkysva/
├── .github/
│ ├── CODEOWNERS
│ ├── dependabot.yml
│ └── workflows/
│ ├── bandit.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── scorecard.yml
│ ├── test.yml
│ ├── update_coc.yml
│ └── zizmor.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── AUTHORS.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── conftest.py
├── docs/
│ ├── _ext/
│ │ └── djangodummy/
│ │ ├── __init__.py
│ │ ├── requirements.txt
│ │ └── settings.py
│ ├── _static/
│ │ ├── .gitkeep
│ │ └── style.css
│ ├── admin.rst
│ ├── advanced.rst
│ ├── api/
│ │ ├── index.rst
│ │ ├── polymorphic.admin.rst
│ │ ├── polymorphic.contrib/
│ │ │ ├── drf.rst
│ │ │ ├── extra_views.rst
│ │ │ ├── guardian.rst
│ │ │ └── index.rst
│ │ ├── polymorphic.deletion.rst
│ │ ├── polymorphic.formsets.rst
│ │ ├── polymorphic.managers.rst
│ │ ├── polymorphic.models.rst
│ │ ├── polymorphic.showfields.rst
│ │ ├── polymorphic.templatetags/
│ │ │ ├── index.rst
│ │ │ ├── polymorphic_admin_tags.rst
│ │ │ └── polymorphic_formset_tags.rst
│ │ └── polymorphic.utils.rst
│ ├── changelog/
│ │ ├── drf.rst
│ │ └── index.rst
│ ├── conf.py
│ ├── deletion.rst
│ ├── formsets.rst
│ ├── index.rst
│ ├── integrations/
│ │ ├── drf.rst
│ │ └── index.rst
│ ├── managers.rst
│ ├── migrating.rst
│ ├── performance.rst
│ ├── quickstart.rst
│ ├── typing.rst
│ └── views.rst
├── example/
│ ├── example/
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ ├── orders/
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ └── models.py
│ └── pexp/
│ ├── __init__.py
│ ├── admin.py
│ ├── dumpdata_test_correct_output.txt
│ ├── management/
│ │ ├── __init__.py
│ │ └── commands/
│ │ ├── __init__.py
│ │ ├── p2cmd.py
│ │ ├── pcmd.py
│ │ ├── polybench.py
│ │ └── polymorphic_create_test_data.py
│ ├── migrations/
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ └── models.py
├── justfile
├── manage.py
├── pyproject.toml
└── src/
└── polymorphic/
├── __init__.py
├── admin/
│ ├── __init__.py
│ ├── childadmin.py
│ ├── filters.py
│ ├── forms.py
│ ├── generic.py
│ ├── helpers.py
│ ├── inlines.py
│ └── parentadmin.py
├── apps.py
├── base.py
├── contrib/
│ ├── __init__.py
│ ├── drf/
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ └── serializers.py
│ ├── extra_views.py
│ └── guardian.py
├── deletion.py
├── formsets/
│ ├── __init__.py
│ ├── generic.py
│ ├── models.py
│ └── utils.py
├── locale/
│ ├── en/
│ │ └── LC_MESSAGES/
│ │ └── django.po
│ ├── es/
│ │ └── LC_MESSAGES/
│ │ └── django.po
│ └── fr/
│ └── LC_MESSAGES/
│ └── django.po
├── managers.py
├── models.py
├── py.typed
├── query.py
├── query_translate.py
├── related_descriptors.py
├── showfields.py
├── static/
│ └── polymorphic/
│ ├── css/
│ │ └── polymorphic_inlines.css
│ └── js/
│ └── polymorphic_inlines.js
├── templates/
│ └── admin/
│ └── polymorphic/
│ ├── add_type_form.html
│ ├── change_form.html
│ ├── delete_confirmation.html
│ ├── edit_inline/
│ │ └── stacked.html
│ └── object_history.html
├── templatetags/
│ ├── __init__.py
│ ├── polymorphic_admin_tags.py
│ └── polymorphic_formset_tags.py
├── tests/
│ ├── __init__.py
│ ├── admin.py
│ ├── admintestcase.py
│ ├── conftest.py
│ ├── debug.py
│ ├── deletion/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_deletion.py
│ ├── errata/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── settings.py
│ │ └── test_errata.py
│ ├── examples/
│ │ ├── __init__.py
│ │ ├── integrations/
│ │ │ ├── __init__.py
│ │ │ ├── apps.py
│ │ │ ├── drf/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── example_serializers.py
│ │ │ │ ├── filter_serializers.py
│ │ │ │ ├── filter_views.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── example_models.py
│ │ │ │ │ ├── filters.py
│ │ │ │ │ └── models_test.py
│ │ │ │ ├── serializers.py
│ │ │ │ ├── test.py
│ │ │ │ ├── urls.py
│ │ │ │ └── views.py
│ │ │ ├── extra_views/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── templates/
│ │ │ │ │ └── extra_views/
│ │ │ │ │ └── article_formset.html
│ │ │ │ ├── templatetags/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── extra_views_tags.py
│ │ │ │ ├── test.py
│ │ │ │ ├── urls.py
│ │ │ │ └── views.py
│ │ │ ├── guardian/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ └── test.py
│ │ │ ├── migrations/
│ │ │ │ ├── 0001_initial.py
│ │ │ │ └── __init__.py
│ │ │ ├── models.py
│ │ │ └── reversion/
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── apps.py
│ │ │ ├── templates/
│ │ │ │ └── admin/
│ │ │ │ └── polymorphic/
│ │ │ │ └── object_history.html
│ │ │ └── test.py
│ │ ├── type_hints/
│ │ │ ├── __init__.py
│ │ │ ├── fk/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── m2m/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── managers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ ├── models.py
│ │ │ ├── one2one/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apps.py
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 0001_initial.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── models.py
│ │ │ │ └── test.py
│ │ │ └── pyright.json
│ │ └── views/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── templates/
│ │ │ ├── project_form.html
│ │ │ └── project_type_select.html
│ │ ├── test.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── migrations/
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── other/
│ │ ├── migrations/
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_cross_apps.py
│ ├── settings.py
│ ├── test_admin.py
│ ├── test_base.py
│ ├── test_contrib.py
│ ├── test_formsets.py
│ ├── test_inheritance.py
│ ├── test_migration_managers.py
│ ├── test_migrations/
│ │ ├── __init__.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ └── test_on_delete.py
│ ├── test_multidb.py
│ ├── test_orm.py
│ ├── test_performance.py
│ ├── test_query_translate.py
│ ├── test_regression.py
│ ├── test_serialization.py
│ ├── test_signals.py
│ ├── test_templatetags.py
│ ├── test_utils.py
│ ├── urls.py
│ └── utils.py
└── utils.py
SYMBOL INDEX (1405 symbols across 111 files)
FILE: conftest.py
function pytest_configure (line 8) | def pytest_configure(config):
function first_breakable_line (line 15) | def first_breakable_line(obj) -> tuple[str, int]:
function pytest_runtest_call (line 47) | def pytest_runtest_call(item):
function _install_playwright_browsers (line 64) | def _install_playwright_browsers() -> None:
function pytest_collection_modifyitems (line 69) | def pytest_collection_modifyitems(config: pytest.Config, items: list[pyt...
FILE: docs/conf.py
function pypi_role (line 309) | def pypi_role(name, rawtext, text, lineno, inliner, options={}, content=...
function setup (line 317) | def setup(app):
FILE: example/orders/admin.py
class CreditCardPaymentInline (line 8) | class CreditCardPaymentInline(StackedPolymorphicInline.Child):
class BankPaymentInline (line 12) | class BankPaymentInline(StackedPolymorphicInline.Child):
class SepaPaymentInline (line 16) | class SepaPaymentInline(StackedPolymorphicInline.Child):
class PaymentInline (line 20) | class PaymentInline(StackedPolymorphicInline):
class OrderAdmin (line 32) | class OrderAdmin(PolymorphicInlineSupportMixin, admin.ModelAdmin):
FILE: example/orders/migrations/0001_initial.py
class Migration (line 4) | class Migration(migrations.Migration):
FILE: example/orders/models.py
class Order (line 8) | class Order(models.Model):
class Meta (line 15) | class Meta:
method __str__ (line 20) | def __str__(self):
class Payment (line 24) | class Payment(PolymorphicModel):
class Meta (line 33) | class Meta:
method __str__ (line 37) | def __str__(self):
class CreditCardPayment (line 41) | class CreditCardPayment(Payment):
class Meta (line 52) | class Meta:
class BankPayment (line 57) | class BankPayment(Payment):
class Meta (line 65) | class Meta:
class SepaPayment (line 70) | class SepaPayment(Payment):
class Meta (line 78) | class Meta:
FILE: example/pexp/admin.py
class ProjectAdmin (line 11) | class ProjectAdmin(PolymorphicParentModelAdmin):
class ProjectChildAdmin (line 17) | class ProjectChildAdmin(PolymorphicChildModelAdmin):
class UUIDModelAAdmin (line 30) | class UUIDModelAAdmin(PolymorphicParentModelAdmin):
class UUIDModelAChildAdmin (line 35) | class UUIDModelAChildAdmin(PolymorphicChildModelAdmin):
class ProxyAdmin (line 44) | class ProxyAdmin(PolymorphicParentModelAdmin):
class ProxyChildAdmin (line 49) | class ProxyChildAdmin(PolymorphicChildModelAdmin):
FILE: example/pexp/management/commands/p2cmd.py
function show_queries (line 18) | def show_queries():
function print_timing (line 26) | def print_timing(func, message="", iterations=1):
class Command (line 47) | class Command(BaseCommand):
method handle_noargs (line 50) | def handle_noargs(self, **options):
function poly_sql_query (line 88) | def poly_sql_query():
function poly_sql_query2 (line 107) | def poly_sql_query2():
FILE: example/pexp/management/commands/pcmd.py
function reset_queries (line 10) | def reset_queries():
class Command (line 14) | class Command(NoArgsCommand):
method handle_noargs (line 17) | def handle_noargs(self, **options):
FILE: example/pexp/management/commands/polybench.py
function show_queries (line 16) | def show_queries():
function print_timing (line 28) | def print_timing(func, message="", iterations=1):
function run_vanilla_any_poly (line 50) | def run_vanilla_any_poly(func, iterations=1):
function bench_create (line 61) | def bench_create(model):
function bench_load1 (line 71) | def bench_load1(model):
function bench_load1_short (line 76) | def bench_load1_short(model):
function bench_load2 (line 82) | def bench_load2(model):
function bench_load2_short (line 89) | def bench_load2_short(model):
function bench_delete (line 97) | def bench_delete(model):
class Command (line 105) | class Command(BaseCommand):
method handle_noargs (line 108) | def handle_noargs(self, **options):
FILE: example/pexp/management/commands/polymorphic_create_test_data.py
class Command (line 9) | class Command(BaseCommand):
method handle_noargs (line 12) | def handle_noargs(self, **options):
FILE: example/pexp/migrations/0001_initial.py
class Migration (line 6) | class Migration(migrations.Migration):
FILE: example/pexp/models.py
class Project (line 7) | class Project(ShowFieldContent, PolymorphicModel):
class ArtProject (line 13) | class ArtProject(Project):
class ResearchProject (line 17) | class ResearchProject(Project):
class UUIDModelA (line 21) | class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
class UUIDModelB (line 28) | class UUIDModelB(UUIDModelA):
class UUIDModelC (line 32) | class UUIDModelC(UUIDModelB):
class ProxyBase (line 36) | class ProxyBase(PolymorphicModel):
method __unicode__ (line 41) | def __unicode__(self):
class Meta (line 44) | class Meta:
class ProxyA (line 48) | class ProxyA(ProxyBase):
class Meta (line 49) | class Meta:
method __unicode__ (line 52) | def __unicode__(self):
class ProxyB (line 56) | class ProxyB(ProxyBase):
class Meta (line 57) | class Meta:
method __unicode__ (line 60) | def __unicode__(self):
class TestModelA (line 67) | class TestModelA(ShowFieldTypeAndContent, PolymorphicModel):
class TestModelB (line 71) | class TestModelB(TestModelA):
class TestModelC (line 75) | class TestModelC(TestModelB):
class NormalModelA (line 80) | class NormalModelA(models.Model):
class NormalModelB (line 86) | class NormalModelB(NormalModelA):
class NormalModelC (line 90) | class NormalModelC(NormalModelB):
FILE: src/polymorphic/admin/childadmin.py
class ParentAdminNotRegistered (line 31) | class ParentAdminNotRegistered(RuntimeError):
class PolymorphicChildModelAdmin (line 35) | class PolymorphicChildModelAdmin(_ModelAdminBase, Generic[_ModelT]):
method __init__ (line 65) | def __init__(self, model: type[_ModelT], admin_site: Any, *args: Any, ...
method get_form (line 71) | def get_form(
method get_model_perms (line 89) | def get_model_perms(self, request):
method change_form_template (line 97) | def change_form_template(self) -> list[str]: # type: ignore[override]
method delete_confirmation_template (line 117) | def delete_confirmation_template(self) -> list[str]: # type: ignore[o...
method object_history_template (line 137) | def object_history_template(self) -> list[str]: # type: ignore[override]
method _get_parent_admin (line 156) | def _get_parent_admin(self):
method response_post_save_add (line 184) | def response_post_save_add(self, request, obj):
method response_post_save_change (line 187) | def response_post_save_change(self, request, obj):
method render_change_form (line 190) | def render_change_form(self, request, context, add=False, change=False...
method delete_view (line 197) | def delete_view(self, request, object_id, context=None):
method history_view (line 202) | def history_view(self, request, object_id, extra_context=None):
method get_base_fieldsets (line 212) | def get_base_fieldsets(self, request, obj=None):
method get_fieldsets (line 215) | def get_fieldsets(self, request, obj=None):
method get_subclass_fields (line 234) | def get_subclass_fields(self, request, obj=None):
FILE: src/polymorphic/admin/filters.py
class PolymorphicChildModelFilter (line 15) | class PolymorphicChildModelFilter(admin.SimpleListFilter):
method lookups (line 30) | def lookups( # type: ignore[override]
method queryset (line 37) | def queryset(self, request: HttpRequest, queryset: QuerySet[Any]) -> Q...
FILE: src/polymorphic/admin/forms.py
class PolymorphicModelChoiceForm (line 8) | class PolymorphicModelChoiceForm(forms.Form):
method __init__ (line 20) | def __init__(self, *args: Any, **kwargs: Any) -> None:
FILE: src/polymorphic/admin/generic.py
class GenericPolymorphicInlineModelAdmin (line 20) | class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, Ge...
method get_formset (line 28) | def get_formset( # type: ignore[override]
class Child (line 48) | class Child(PolymorphicInlineModelAdmin.Child):
method content_type (line 59) | def content_type(self) -> ContentType:
method get_formset_child (line 66) | def get_formset_child(
class GenericStackedPolymorphicInline (line 78) | class GenericStackedPolymorphicInline(GenericPolymorphicInlineModelAdmin):
FILE: src/polymorphic/admin/helpers.py
class PolymorphicInlineAdminForm (line 20) | class PolymorphicInlineAdminForm(InlineAdminForm):
method polymorphic_ctype_field (line 25) | def polymorphic_ctype_field(self) -> AdminField:
method is_empty (line 29) | def is_empty(self) -> bool:
class PolymorphicInlineAdminFormSet (line 35) | class PolymorphicInlineAdminFormSet(InlineAdminFormSet):
method __init__ (line 43) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method __iter__ (line 49) | def __iter__(self) -> Iterator[PolymorphicInlineAdminForm]:
method get_child_fieldsets (line 84) | def get_child_fieldsets(self, child_inline: Any) -> list[tuple[str | N...
method get_child_readonly_fields (line 87) | def get_child_readonly_fields(self, child_inline: Any) -> list[str]:
method get_child_prepopulated_fields (line 90) | def get_child_prepopulated_fields(self, child_inline: Any) -> dict[str...
method inline_formset_data (line 95) | def inline_formset_data(self) -> str:
class PolymorphicInlineSupportMixin (line 121) | class PolymorphicInlineSupportMixin:
method get_inline_formsets (line 134) | def get_inline_formsets(
FILE: src/polymorphic/admin/inlines.py
class PolymorphicInlineModelAdmin (line 35) | class PolymorphicInlineModelAdmin(InlineModelAdmin):
method __init__ (line 69) | def __init__(self, parent_model: type[models.Model], admin_site: Admin...
method get_child_inlines (line 91) | def get_child_inlines(self) -> list[type["PolymorphicInlineModelAdmin....
method get_child_inline_instances (line 101) | def get_child_inline_instances(self) -> list["PolymorphicInlineModelAd...
method get_child_inline_instance (line 110) | def get_child_inline_instance(
method get_formset (line 123) | def get_formset(
method get_formset_children (line 144) | def get_formset_children(
method get_fieldsets (line 157) | def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> "_Fi...
method get_fields (line 166) | def get_fields(self, request: HttpRequest, obj: Any = None) -> "_Field...
method media (line 174) | def media(self):
class Child (line 194) | class Child(InlineModelAdmin):
method __init__ (line 211) | def __init__(self, parent_inline: "PolymorphicInlineModelAdmin") -> ...
method get_formset (line 217) | def get_formset(self, request: HttpRequest, obj: Any = None, **kwarg...
method get_fields (line 223) | def get_fields(self, request: HttpRequest, obj: Any = None) -> "_Fie...
method get_formset_child (line 238) | def get_formset_child(
class StackedPolymorphicInline (line 289) | class StackedPolymorphicInline(PolymorphicInlineModelAdmin):
FILE: src/polymorphic/admin/parentadmin.py
class RegistrationClosed (line 35) | class RegistrationClosed(RuntimeError):
class ChildAdminNotRegistered (line 39) | class ChildAdminNotRegistered(RuntimeError):
class PolymorphicParentModelAdmin (line 43) | class PolymorphicParentModelAdmin(_ModelAdminBase, Generic[_ModelT]):
method __init__ (line 76) | def __init__(self, model: type[_ModelT], admin_site: Any, *args: Any, ...
method _lazy_setup (line 83) | def _lazy_setup(self):
method get_child_models (line 102) | def get_child_models(self):
method get_child_type_choices (line 115) | def get_child_type_choices(self, request, action):
method _get_real_admin (line 134) | def _get_real_admin(self, object_id, super_if_self=True):
method _get_real_admin_by_ct (line 143) | def _get_real_admin_by_ct(self, ct_id, super_if_self=True):
method _get_real_admin_by_model (line 157) | def _get_real_admin_by_model(self, model_class, super_if_self=True):
method get_queryset (line 179) | def get_queryset(self, request):
method add_view (line 186) | def add_view(self, request, form_url="", extra_context=None):
method change_view (line 206) | def change_view(self, request, object_id, *args, **kwargs):
method changeform_view (line 211) | def changeform_view(self, request, object_id=None, *args, **kwargs):
method history_view (line 222) | def history_view(self, request, object_id, extra_context=None):
method delete_view (line 227) | def delete_view(self, request, object_id, extra_context=None):
method get_urls (line 232) | def get_urls(self):
method add_type_view (line 243) | def add_type_view(self, request, form_url=""):
method render_add_type_form (line 289) | def render_add_type_form(self, request, context, form_url=""):
method change_list_template (line 317) | def change_list_template(self) -> list[str]: # type: ignore[override]
FILE: src/polymorphic/apps.py
function check_reserved_field_names (line 9) | def check_reserved_field_names(
function _check_polymorphic_managers (line 28) | def _check_polymorphic_managers(model: type[models.Model]) -> list[Check...
function _check_model_reserved_field_names (line 71) | def _check_model_reserved_field_names(model: type[models.Model]) -> list...
class PolymorphicConfig (line 89) | class PolymorphicConfig(AppConfig):
method ready (line 93) | def ready(self) -> None:
FILE: src/polymorphic/base.py
class ManagerInheritanceWarning (line 26) | class ManagerInheritanceWarning(RuntimeWarning):
function polymorphic_base_manager (line 43) | def polymorphic_base_manager(self):
class PolymorphicModelBase (line 66) | class PolymorphicModelBase(ModelBase):
method __new__ (line 103) | def __new__(
method base_objects (line 156) | def base_objects(self) -> models.Manager[Any]:
method _base_objects (line 166) | def _base_objects(self) -> models.Manager[Any]:
method _default_manager (line 177) | def _default_manager(cls) -> PolymorphicManager[Any]:
method _base_manager (line 215) | def _base_manager(cls) -> PolymorphicManager[Any]:
FILE: src/polymorphic/contrib/drf/serializers.py
class PolymorphicSerializer (line 9) | class PolymorphicSerializer(serializers.Serializer):
method __new__ (line 13) | def __new__(cls, *args, **kwargs):
method __init__ (line 26) | def __init__(self, *args, **kwargs):
method to_resource_type (line 45) | def to_resource_type(self, model_or_instance):
method to_representation (line 48) | def to_representation(self, instance):
method to_internal_value (line 60) | def to_internal_value(self, data):
method create (line 72) | def create(self, validated_data):
method update (line 77) | def update(self, instance, validated_data):
method is_valid (line 82) | def is_valid(self, *args, **kwargs):
method run_validation (line 104) | def run_validation(self, data=empty):
method _to_model (line 119) | def _to_model(self, model_or_instance):
method _get_resource_type_from_mapping (line 126) | def _get_resource_type_from_mapping(self, mapping):
method _get_serializer_from_model_or_instance (line 136) | def _get_serializer_from_model_or_instance(self, model_or_instance):
method _get_serializer_from_resource_type (line 150) | def _get_serializer_from_resource_type(self, resource_type):
FILE: src/polymorphic/contrib/extra_views.py
class PolymorphicFormSetMixin (line 30) | class PolymorphicFormSetMixin:
method get_formset_children (line 44) | def get_formset_children(self) -> list[PolymorphicFormSetChild]:
method get_formset_child_kwargs (line 54) | def get_formset_child_kwargs(self) -> dict[str, Any]:
method get_formset (line 57) | def get_formset(self) -> type[BaseFormSet]:
class PolymorphicFormSetView (line 72) | class PolymorphicFormSetView(PolymorphicFormSetMixin, extra_views.ModelF...
class PolymorphicInlineFormSetView (line 93) | class PolymorphicInlineFormSetView(PolymorphicFormSetMixin, extra_views....
class PolymorphicInlineFormSet (line 115) | class PolymorphicInlineFormSet(PolymorphicFormSetMixin, extra_views.Inli...
FILE: src/polymorphic/contrib/guardian.py
function get_polymorphic_base_content_type (line 9) | def get_polymorphic_base_content_type(obj: Any) -> ContentType:
FILE: src/polymorphic/deletion.py
function migration_fingerprint (line 19) | def migration_fingerprint(value: Any) -> Any:
class PolymorphicGuard (line 40) | class PolymorphicGuard:
method __init__ (line 51) | def __init__(self, action: Callable[..., Any]) -> None:
method __call__ (line 56) | def __call__(
method migration_key (line 84) | def migration_key(self) -> Any:
method __eq__ (line 87) | def __eq__(self, other: object) -> bool:
method __hash__ (line 114) | def __hash__(self) -> int:
class PolymorphicGuardSerializer (line 118) | class PolymorphicGuardSerializer(BaseSerializer):
method serialize (line 128) | def serialize(self) -> tuple[str, set[str]]:
FILE: src/polymorphic/formsets/generic.py
class GenericPolymorphicFormSetChild (line 21) | class GenericPolymorphicFormSetChild(PolymorphicFormSetChild):
method __init__ (line 29) | def __init__(
method get_form (line 40) | def get_form(
class BaseGenericPolymorphicInlineFormSet (line 70) | class BaseGenericPolymorphicInlineFormSet(BaseGenericInlineFormSet, Base...
function generic_polymorphic_inlineformset_factory (line 76) | def generic_polymorphic_inlineformset_factory(
FILE: src/polymorphic/formsets/models.py
class UnsupportedChildType (line 27) | class UnsupportedChildType(LookupError):
class PolymorphicFormSetChild (line 31) | class PolymorphicFormSetChild:
method __init__ (line 47) | def __init__(
method content_type (line 77) | def content_type(self) -> ContentType:
method get_form (line 84) | def get_form(self, **kwargs: Any) -> type[ModelForm[Any]]:
function polymorphic_child_forms_factory (line 137) | def polymorphic_child_forms_factory(
class BasePolymorphicModelFormSet (line 154) | class BasePolymorphicModelFormSet(BaseModelFormSet):
method __init__ (line 170) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method _construct_form (line 174) | def _construct_form(self, i: int, **kwargs: Any) -> BaseForm:
method add_fields (line 283) | def add_fields(self, form: BaseForm, index: int | None) -> None:
method get_form_class (line 296) | def get_form_class(self, model: type[models.Model]) -> type[ModelForm[...
method is_multipart (line 314) | def is_multipart(self) -> bool:
method media (line 322) | def media(self) -> Media:
method empty_forms (line 331) | def empty_forms(self) -> list[BaseForm]:
method empty_form (line 351) | def empty_form(self) -> BaseForm:
function polymorphic_modelformset_factory (line 358) | def polymorphic_modelformset_factory(
class BasePolymorphicInlineFormSet (line 429) | class BasePolymorphicInlineFormSet(BaseInlineFormSet, BasePolymorphicMod...
method _construct_form (line 434) | def _construct_form(self, i: int, **kwargs: Any) -> BaseForm:
function polymorphic_inlineformset_factory (line 438) | def polymorphic_inlineformset_factory(
FILE: src/polymorphic/formsets/utils.py
function add_media (line 8) | def add_media(dest: Media, media: Media) -> None:
FILE: src/polymorphic/managers.py
class PolymorphicManager (line 75) | class PolymorphicManager(models.Manager[_All], Generic[_All, _Base]):
method all (line 87) | def all(self) -> PolymorphicQuerySet[_All, _Base]: ...
method filter (line 88) | def filter(self, *args: Any, **kwargs: Any) -> PolymorphicQuerySet[_Al...
method from_queryset (line 91) | def from_queryset(
method get_queryset (line 99) | def get_queryset(self) -> PolymorphicQuerySet[_All, _Base]:
method __str__ (line 105) | def __str__(self) -> str:
method non_polymorphic (line 111) | def non_polymorphic(self) -> PolymorphicQuerySet[_Base, _Base]:
method instance_of (line 116) | def instance_of(self, __a: type[_A], /) -> PolymorphicQuerySet[_A, _Ba...
method instance_of (line 119) | def instance_of(
method instance_of (line 124) | def instance_of(
method instance_of (line 129) | def instance_of(
method instance_of (line 134) | def instance_of(self, *args: type[PolymorphicModel]) -> PolymorphicQue...
method instance_of (line 136) | def instance_of(
method not_instance_of (line 141) | def not_instance_of(self, *args: type[PolymorphicModel]) -> Polymorphi...
method get_real_instances (line 144) | def get_real_instances(self, base_result_objects: Iterable[_All] | Non...
method create_from_super (line 147) | def create_from_super(self, obj: models.Model, **kwargs: Any) -> _Base:
class PolymorphicManyRelatedManager (line 199) | class PolymorphicManyRelatedManager( # type: ignore[type-var]
class PolymorphicRelatedManager (line 205) | class PolymorphicRelatedManager( # type: ignore[type-var]
class PolymorphicRelatedManager (line 213) | class PolymorphicRelatedManager(PolymorphicManager[_All, _Base], Generic...
class PolymorphicManyRelatedManager (line 215) | class PolymorphicManyRelatedManager(
class PolymorphicManyToManyDescriptor (line 221) | class PolymorphicManyToManyDescriptor(ManyToManyDescriptor, Generic[_All...
method __get__ (line 241) | def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
method __get__ (line 244) | def __get__(
method __get__ (line 248) | def __get__(
class PolymorphicReverseManyToOneDescriptor (line 257) | class PolymorphicReverseManyToOneDescriptor(
method __get__ (line 285) | def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
method __get__ (line 288) | def __get__(
method __get__ (line 292) | def __get__(
class PolymorphicForwardManyToOneDescriptor (line 300) | class PolymorphicForwardManyToOneDescriptor(
method __get__ (line 328) | def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
method __get__ (line 331) | def __get__(
method __get__ (line 339) | def __get__(
method __get__ (line 346) | def __get__(
method get_queryset (line 353) | def get_queryset(self, **hints: Any) -> PolymorphicQuerySet[_All, _Base]:
class PolymorphicForwardOneToOneDescriptor (line 360) | class PolymorphicForwardOneToOneDescriptor(
class PolymorphicReverseOneToOneDescriptor (line 390) | class PolymorphicReverseOneToOneDescriptor(
method __get__ (line 419) | def __get__(self, instance: None, cls: Any | None = None, /) -> Self: ...
method __get__ (line 422) | def __get__(
method __get__ (line 430) | def __get__(
method __get__ (line 437) | def __get__(
method get_queryset (line 444) | def get_queryset(self, **hints: Any) -> PolymorphicQuerySet[_All, _Base]:
FILE: src/polymorphic/models.py
class PolymorphicTypeUndefined (line 28) | class PolymorphicTypeUndefined(LookupError): ...
class PolymorphicTypeInvalid (line 31) | class PolymorphicTypeInvalid(RuntimeError): ...
class PolymorphicModel (line 34) | class PolymorphicModel(models.Model, metaclass=PolymorphicModelBase):
class Meta (line 68) | class Meta:
method polymorphic_primary_key_name (line 72) | def polymorphic_primary_key_name(cls) -> str:
method translate_polymorphic_Q_object (line 88) | def translate_polymorphic_Q_object(cls, q: Q) -> Q:
method pre_save_polymorphic (line 91) | def pre_save_polymorphic(self, using: str = DEFAULT_DB_ALIAS) -> None:
method save (line 122) | def save(
method get_real_instance_class (line 151) | def get_real_instance_class(self) -> type[Self] | None:
method get_real_concrete_instance_class_id (line 194) | def get_real_concrete_instance_class_id(self) -> int | None:
method get_real_concrete_instance_class (line 204) | def get_real_concrete_instance_class(self) -> type[Self] | None:
method get_real_instance (line 215) | def get_real_instance(self) -> Self:
method delete (line 242) | def delete(
FILE: src/polymorphic/query.py
class BasePolymorphicModelIterable (line 48) | class BasePolymorphicModelIterable(ModelIterable[_All]):
class BasePolymorphicModelIterable (line 52) | class BasePolymorphicModelIterable(ModelIterable):
class _Inconsistent (line 56) | class _Inconsistent:
class PolymorphicModelIterable (line 65) | class PolymorphicModelIterable(BasePolymorphicModelIterable, Generic[_Al...
method __iter__ (line 75) | def __iter__(self) -> Iterator[_All]:
method _polymorphic_iterator (line 81) | def _polymorphic_iterator(self, base_iter: Iterator[_All]) -> Iterator...
function transmogrify (line 125) | def transmogrify(cls: type[_All], obj: models.Model) -> _All:
class PolymorphicQuerySet (line 146) | class PolymorphicQuerySet(QuerySet[_All], Generic[_All, _Base]):
method __init__ (line 159) | def __init__(self, *args: Any, **kwargs: Any) -> None:
method _clone (line 171) | def _clone(self, *args: Any, **kwargs: Any) -> Self:
method as_manager (line 182) | def as_manager(cls) -> models.Manager[_All]:
method bulk_create (line 196) | def bulk_create(
method non_polymorphic (line 210) | def non_polymorphic(self) -> PolymorphicQuerySet[_Base, _Base]:
method instance_of (line 221) | def instance_of(self, __a: type[_A], /) -> PolymorphicQuerySet[_A, _Ba...
method instance_of (line 224) | def instance_of(
method instance_of (line 229) | def instance_of(
method instance_of (line 234) | def instance_of(
method instance_of (line 239) | def instance_of(self, *args: type["PolymorphicModel"]) -> PolymorphicQ...
method instance_of (line 241) | def instance_of(
method not_instance_of (line 248) | def not_instance_of(self, *args: type["PolymorphicModel"]) -> Self:
method _filter_or_exclude (line 253) | def _filter_or_exclude(self, negate: bool, args: Any, kwargs: Any) -> ...
method order_by (line 265) | def order_by(self, *field_names: str | Combinable) -> Self:
method defer (line 276) | def defer(self, field: None, /) -> Self: ...
method defer (line 278) | def defer(self, *fields: str) -> Self: ...
method defer (line 279) | def defer(self, *fields: str | None) -> Self:
method only (line 298) | def only(self, *fields: str) -> Self:
method _polymorphic_add_deferred_loading (line 312) | def _polymorphic_add_deferred_loading(self, field_names: Iterable[str]...
method _polymorphic_add_immediate_loading (line 325) | def _polymorphic_add_immediate_loading(self, field_names: Iterable[str...
method _process_aggregate_args (line 344) | def _process_aggregate_args(self, args: Sequence[Any], kwargs: dict[st...
method annotate (line 398) | def annotate(self, *args: Any, **kwargs: Any) -> Self:
method aggregate (line 404) | def aggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
method _values (line 414) | def _values(self, *args: Any, **kwargs: Any) -> Self:
method _get_real_instances (line 425) | def _get_real_instances(self, base_result_objects: Sequence[_All]) -> ...
method __repr__ (line 655) | def __repr__(self, *args, **kwargs):
class _p_list_class (line 662) | class _p_list_class(list[Any]):
method __repr__ (line 663) | def __repr__(self, *args: Any, **kwargs: Any) -> str:
method get_real_instances (line 667) | def get_real_instances(self, base_result_objects: Iterable[_All] | Non...
method delete (line 694) | def delete(self) -> tuple[int, dict[str, int]]:
FILE: src/polymorphic/query_translate.py
function translate_polymorphic_filter_definitions_in_kwargs (line 29) | def translate_polymorphic_filter_definitions_in_kwargs(
function translate_polymorphic_Q_object (line 63) | def translate_polymorphic_Q_object(
function translate_polymorphic_filter_definitions_in_args (line 91) | def translate_polymorphic_filter_definitions_in_args(
function _translate_polymorphic_filter_definition (line 108) | def _translate_polymorphic_filter_definition(
function translate_polymorphic_field_path (line 140) | def translate_polymorphic_field_path(queryset_model: type[models.Model],...
function _create_base_path (line 205) | def _create_base_path(baseclass: type[models.Model], myclass: type[model...
function _get_query_related_name (line 221) | def _get_query_related_name(myclass: type[models.Model]) -> str:
function create_instanceof_q (line 231) | def create_instanceof_q(
function _get_mro_content_type_ids (line 277) | def _get_mro_content_type_ids(
FILE: src/polymorphic/related_descriptors.py
class NonPolymorphicForwardOneToOneDescriptor (line 10) | class NonPolymorphicForwardOneToOneDescriptor(ForwardOneToOneDescriptor):
method get_queryset (line 17) | def get_queryset(self, **hints: Any) -> QuerySet[Any]:
class NonPolymorphicReverseOneToOneDescriptor (line 33) | class NonPolymorphicReverseOneToOneDescriptor(ReverseOneToOneDescriptor):
method get_queryset (line 40) | def get_queryset(self, **hints: Any) -> QuerySet[Any]:
FILE: src/polymorphic/showfields.py
class ShowFieldBase (line 16) | class ShowFieldBase(_Base):
method __repr__ (line 31) | def __repr__(self) -> str:
method _showfields_get_content (line 34) | def _showfields_get_content(self, field_name: str, field_type: type = ...
method _showfields_add_regular_fields (line 60) | def _showfields_add_regular_fields(self, parts: list[tuple[bool, str, ...
method _showfields_add_dynamic_fields (line 89) | def _showfields_add_dynamic_fields(
method __str__ (line 104) | def __str__(self) -> str:
class ShowFieldType (line 170) | class ShowFieldType(ShowFieldBase):
class ShowFieldContent (line 176) | class ShowFieldContent(ShowFieldBase):
class ShowFieldTypeAndContent (line 182) | class ShowFieldTypeAndContent(ShowFieldBase):
FILE: src/polymorphic/templatetags/polymorphic_admin_tags.py
class BreadcrumbScope (line 8) | class BreadcrumbScope(Node):
method __init__ (line 12) | def __init__(self, base_opts: FilterExpression, nodelist: NodeList) ->...
method parse (line 17) | def parse(cls, parser: Parser, token: Token) -> Self:
method render (line 29) | def render(self, context: Context) -> str:
function breadcrumb_scope (line 49) | def breadcrumb_scope(parser: Parser, token: Token) -> BreadcrumbScope:
FILE: src/polymorphic/templatetags/polymorphic_formset_tags.py
function include_empty_form (line 77) | def include_empty_form(formset: BaseFormSet) -> Generator[BaseForm, None...
function as_script_options (line 95) | def as_script_options(formset: "BaseModelFormSet[Any, Any]") -> str:
function as_form_type (line 132) | def as_form_type(form: "ModelForm[Any]") -> str:
function as_model_name (line 143) | def as_model_name(model: type[models.Model]) -> str:
FILE: src/polymorphic/tests/admin.py
class Model2Admin (line 41) | class Model2Admin(PolymorphicParentModelAdmin):
class Model2DAdmin (line 51) | class Model2DAdmin(PolymorphicChildModelAdmin):
class PlainAAdmin (line 56) | class PlainAAdmin(ModelAdmin):
method get_queryset (line 59) | def get_queryset(self, request: HttpRequest) -> QuerySet:
class Inline (line 63) | class Inline(StackedPolymorphicInline):
method get_child_inlines (line 66) | def get_child_inlines(self):
class InlineModelAChild (line 73) | class InlineModelAChild(StackedPolymorphicInline.Child):
class InlineModelBChild (line 76) | class InlineModelBChild(StackedPolymorphicInline.Child):
class InlineParentAdmin (line 82) | class InlineParentAdmin(PolymorphicInlineSupportMixin, ModelAdmin):
class NoChildrenAdmin (line 88) | class NoChildrenAdmin(PolymorphicParentModelAdmin):
class ModelWithPolyFKAdmin (line 93) | class ModelWithPolyFKAdmin(ModelAdmin):
class M2MAdminTestAdmin (line 98) | class M2MAdminTestAdmin(PolymorphicParentModelAdmin):
class M2MAdminTestChildA (line 104) | class M2MAdminTestChildA(PolymorphicChildModelAdmin):
class M2MAdminTestChildB (line 109) | class M2MAdminTestChildB(PolymorphicChildModelAdmin):
class M2MAdminTestChildC (line 114) | class M2MAdminTestChildC(PolymorphicChildModelAdmin):
class M2MThroughBaseAdmin (line 121) | class M2MThroughBaseAdmin(PolymorphicParentModelAdmin):
class M2MThroughProjectAdmin (line 133) | class M2MThroughProjectAdmin(PolymorphicChildModelAdmin):
class M2MThroughPersonAdmin (line 140) | class M2MThroughPersonAdmin(PolymorphicChildModelAdmin):
class M2MThroughSpecialPersonAdmin (line 147) | class M2MThroughSpecialPersonAdmin(PolymorphicChildModelAdmin):
class DirectM2MContainerAdmin (line 154) | class DirectM2MContainerAdmin(ModelAdmin):
class M2MThroughMembershipInline (line 165) | class M2MThroughMembershipInline(StackedPolymorphicInline):
class MembershipWithPersonChild (line 174) | class MembershipWithPersonChild(StackedPolymorphicInline.Child):
class MembershipWithSpecialPersonChild (line 179) | class MembershipWithSpecialPersonChild(StackedPolymorphicInline.Child):
class M2MThroughProjectWithTeamAdmin (line 191) | class M2MThroughProjectWithTeamAdmin(PolymorphicInlineSupportMixin, Poly...
FILE: src/polymorphic/tests/admintestcase.py
class AdminTestCase (line 11) | class AdminTestCase(TestCase):
method setUpClass (line 22) | def setUpClass(cls):
method setUp (line 28) | def setUp(self):
method tearDown (line 37) | def tearDown(self):
method register (line 41) | def register(self, model):
method admin_register (line 50) | def admin_register(self, model, admin_site):
method get_admin_instance (line 58) | def get_admin_instance(self, model):
method tearDownClass (line 65) | def tearDownClass(cls):
method get_add_url (line 70) | def get_add_url(self, model):
method get_changelist_url (line 74) | def get_changelist_url(self, model):
method get_change_url (line 78) | def get_change_url(self, model, object_id):
method get_history_url (line 82) | def get_history_url(self, model, object_id):
method get_delete_url (line 86) | def get_delete_url(self, model, object_id):
method admin_get_add (line 90) | def admin_get_add(self, model, qs=""):
method admin_post_add (line 100) | def admin_post_add(self, model, formdata, qs=""):
method admin_get_changelist (line 110) | def admin_get_changelist(self, model):
method admin_get_change (line 120) | def admin_get_change(self, model, object_id, query=None, **extra):
method admin_post_change (line 132) | def admin_post_change(self, model, object_id, formdata, **extra):
method admin_get_history (line 144) | def admin_get_history(self, model, object_id, query=None, **extra):
method admin_get_delete (line 156) | def admin_get_delete(self, model, object_id, query=None, **extra):
method admin_post_delete (line 168) | def admin_post_delete(self, model, object_id, **extra):
method create_admin_request (line 181) | def create_admin_request(self, method, url, data=None, **extra):
method assertFormSuccess (line 208) | def assertFormSuccess(self, request_url, response):
FILE: src/polymorphic/tests/conftest.py
function pytest_collection_modifyitems (line 9) | def pytest_collection_modifyitems(config: pytest.Config, items: list[pyt...
FILE: src/polymorphic/tests/deletion/migrations/0001_initial.py
class Migration (line 10) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/deletion/models.py
function project_directory_path (line 8) | def project_directory_path(instance, filename):
class Standalone (line 16) | class Standalone(models.Model):
class PlainA (line 20) | class PlainA(models.Model):
class PlainB1 (line 26) | class PlainB1(PlainA):
class PlainB2 (line 30) | class PlainB2(PlainA):
class PlainC1 (line 36) | class PlainC1(PlainB1):
class RelatedToChild (line 42) | class RelatedToChild(models.Model):
class Base (line 48) | class Base(models.Model):
class Child (line 52) | class Child(Base):
class GrandChild (line 56) | class GrandChild(Child):
class RelatedToGrandChild (line 60) | class RelatedToGrandChild(models.Model):
class Normal1 (line 78) | class Normal1(models.Model):
class Poly1 (line 82) | class Poly1(PolymorphicModel):
class A1 (line 86) | class A1(Poly1):
class B1 (line 90) | class B1(Poly1):
class C1 (line 94) | class C1(Poly1):
class Normal2 (line 108) | class Normal2(models.Model):
class Poly2 (line 112) | class Poly2(PolymorphicModel):
class A2 (line 116) | class A2(Poly2):
class B2 (line 120) | class B2(Poly2):
class C2 (line 124) | class C2(Poly2):
class Normal3 (line 139) | class Normal3(models.Model):
class Poly3 (line 143) | class Poly3(PolymorphicModel, Normal3):
class A3 (line 147) | class A3(Poly3):
class B3 (line 151) | class B3(Poly3):
class Normal4 (line 165) | class Normal4(models.Model):
class Poly4 (line 169) | class Poly4(PolymorphicModel):
class A4 (line 173) | class A4(Poly4):
class B4 (line 177) | class B4(Poly4):
class C4 (line 181) | class C4(Poly4):
class Normal4_1 (line 185) | class Normal4_1(models.Model):
class Poly4_1 (line 189) | class Poly4_1(PolymorphicModel):
class A4_1 (line 193) | class A4_1(Poly4_1):
class B4_1 (line 197) | class B4_1(Poly4_1):
class C4_1 (line 201) | class C4_1(Poly4_1):
class Normal5 (line 216) | class Normal5(models.Model):
class Poly5 (line 220) | class Poly5(PolymorphicModel, Normal5):
class A5 (line 224) | class A5(Poly5):
class B5 (line 228) | class B5(Poly5):
class A_160 (line 243) | class A_160(models.Model):
class B_160 (line 247) | class B_160(PolymorphicModel):
class B1_160 (line 251) | class B1_160(B_160):
class B2_160 (line 255) | class B2_160(B_160):
class C_160 (line 259) | class C_160(models.Model):
class A_160Plain (line 264) | class A_160Plain(models.Model):
class B_160Plain (line 268) | class B_160Plain(models.Model):
class B1_160Plain (line 272) | class B1_160Plain(B_160Plain):
class B2_160Plain (line 276) | class B2_160Plain(B_160Plain):
class C_160Plain (line 280) | class C_160Plain(models.Model):
class Farm (line 290) | class Farm(models.Model):
class Animal (line 294) | class Animal(PolymorphicModel):
class Dog (line 301) | class Dog(Animal):
class Cat (line 305) | class Cat(Animal):
class A_274 (line 313) | class A_274(PolymorphicModel):
class B_274 (line 317) | class B_274(A_274):
class D_274 (line 321) | class D_274(A_274):
class E_274 (line 325) | class E_274(D_274):
class C_274 (line 329) | class C_274(B_274):
class Order (line 338) | class Order(models.Model):
class Meta (line 341) | class Meta:
method __str__ (line 344) | def __str__(self):
class Payment (line 348) | class Payment(PolymorphicModel):
class Meta (line 353) | class Meta:
class CreditCardPayment (line 357) | class CreditCardPayment(Payment):
class Beneficiary (line 361) | class Beneficiary(models.Model):
class SepaPayment (line 366) | class SepaPayment(Payment):
class A_540 (line 384) | class A_540(PolymorphicModel):
class B_540 (line 388) | class B_540(A_540):
class CustomModel (line 397) | class CustomModel(models.Model):
class Project (line 401) | class Project(CustomModel):
class DatasetFolder (line 407) | class DatasetFolder(CustomModel):
class OriginalFile (line 411) | class OriginalFile(PolymorphicModel, CustomModel):
class DatasetRelation (line 419) | class DatasetRelation(OriginalFile):
class OriginalDataset (line 424) | class OriginalDataset(OriginalFile):
class OriginalImage (line 435) | class OriginalImage(OriginalFile):
class PolyDevice (line 445) | class PolyDevice(models.Model):
class PolyInterface (line 449) | class PolyInterface(PolymorphicModel):
class PolyEthernetInterface (line 454) | class PolyEthernetInterface(PolyInterface):
class PolyModularInterface (line 458) | class PolyModularInterface(PolyEthernetInterface):
class PolyFixedInterface (line 462) | class PolyFixedInterface(PolyEthernetInterface):
class PolyWirelessInterface (line 466) | class PolyWirelessInterface(PolyInterface):
class PolyFCInterface (line 470) | class PolyFCInterface(PolyInterface):
class Poll (line 474) | class Poll(models.Model):
class Question (line 478) | class Question(models.Model):
class Answer (line 482) | class Answer(PolymorphicModel):
class TextAnswer (line 486) | class TextAnswer(Answer):
class YesNoAnswer (line 490) | class YesNoAnswer(Answer):
FILE: src/polymorphic/tests/deletion/test_deletion.py
class TestDeletion (line 12) | class TestDeletion(TestCase):
method setUp (line 13) | def setUp(self):
method tearDown (line 19) | def tearDown(self):
method test_deletion_bug_160 (line 24) | def test_deletion_bug_160(self):
method test_deletion_bug_229 (line 55) | def test_deletion_bug_229(self):
method test_deletion_bug_274 (line 94) | def test_deletion_bug_274(self):
method test_deletion_bug_357 (line 111) | def test_deletion_bug_357(self):
method test_deletion_bug_540 (line 139) | def test_deletion_bug_540(self):
method test_deletion_bug_547 (line 153) | def test_deletion_bug_547(self):
method test_deletion_bug_608 (line 202) | def test_deletion_bug_608(self):
method test_deletion_bug_608_2 (line 228) | def test_deletion_bug_608_2(self):
method test_vanilla_deletion (line 247) | def test_vanilla_deletion(self):
method test_polymorphic_deletion_scenario1 (line 414) | def test_polymorphic_deletion_scenario1(self):
method test_polymorphic_deletion_scenario2 (line 478) | def test_polymorphic_deletion_scenario2(self):
method test_polymorphic_deletion_scenario3 (line 535) | def test_polymorphic_deletion_scenario3(self):
method test_polymorphic_deletion_scenario4 (line 569) | def test_polymorphic_deletion_scenario4(self):
method test_polymorphic_deletion_scenario4_1 (line 629) | def test_polymorphic_deletion_scenario4_1(self):
method test_polymorphic_deletion_scenario5 (line 689) | def test_polymorphic_deletion_scenario5(self):
method test_raw_delete_results (line 743) | def test_raw_delete_results(self):
method test_delete_keep_parents (line 777) | def test_delete_keep_parents(self):
FILE: src/polymorphic/tests/errata/models.py
class BadModel (line 8) | class BadModel(PolymorphicModel):
class PolymorphicMigrationManager (line 13) | class PolymorphicMigrationManager(PolymorphicManager):
class OkMigrationManager (line 17) | class OkMigrationManager(Manager):
class GoodMigrationManager (line 21) | class GoodMigrationManager(PolymorphicModel):
class BadMigrationManager (line 26) | class BadMigrationManager(PolymorphicModel):
class BadManager (line 30) | class BadManager(PolymorphicModel):
class BadQuerySet (line 34) | class BadQuerySet(PolymorphicModel):
FILE: src/polymorphic/tests/errata/test_errata.py
class TestErrata (line 14) | class TestErrata(SimpleTestCase):
method test_system_checks (line 15) | def test_system_checks(self):
method test_polymorphic_guard_requires_callable (line 45) | def test_polymorphic_guard_requires_callable(self):
class TestFilterErrata (line 63) | class TestFilterErrata(TestCase):
method test_invalid_field_lookup_raises_field_error (line 64) | def test_invalid_field_lookup_raises_field_error(self):
FILE: src/polymorphic/tests/examples/integrations/apps.py
class IntegrationsExampleConfig (line 4) | class IntegrationsExampleConfig(AppConfig):
FILE: src/polymorphic/tests/examples/integrations/drf/apps.py
class DRFExampleConfig (line 4) | class DRFExampleConfig(AppConfig):
FILE: src/polymorphic/tests/examples/integrations/drf/example_serializers.py
class ProjectSerializer (line 8) | class ProjectSerializer(serializers.ModelSerializer):
class Meta (line 9) | class Meta:
class ArtProjectSerializer (line 14) | class ArtProjectSerializer(serializers.ModelSerializer):
class Meta (line 15) | class Meta:
class ResearchProjectSerializer (line 26) | class ResearchProjectSerializer(serializers.ModelSerializer):
class Meta (line 27) | class Meta:
class ProjectPolymorphicSerializer (line 32) | class ProjectPolymorphicSerializer(PolymorphicSerializer):
FILE: src/polymorphic/tests/examples/integrations/drf/filter_serializers.py
class AiModelAnnotatorSerializer (line 6) | class AiModelAnnotatorSerializer(serializers.ModelSerializer):
class Meta (line 7) | class Meta:
class UserAnnotatorSerializer (line 12) | class UserAnnotatorSerializer(serializers.ModelSerializer):
class Meta (line 13) | class Meta:
class AnnotatorSerializer (line 18) | class AnnotatorSerializer(serializers.ModelSerializer):
class Meta (line 19) | class Meta:
class AnnotatorPolymorphicSerializer (line 24) | class AnnotatorPolymorphicSerializer(PolymorphicSerializer):
class AnnotationSerializer (line 32) | class AnnotationSerializer(serializers.ModelSerializer):
class Meta (line 37) | class Meta:
FILE: src/polymorphic/tests/examples/integrations/drf/filter_views.py
class DataFilterSet (line 8) | class DataFilterSet(django_filters.FilterSet):
class Meta (line 13) | class Meta:
method filter_by_ai_model (line 17) | def filter_by_ai_model(self, queryset, name, value):
class AnnotationTrainingViewSet (line 23) | class AnnotationTrainingViewSet(
FILE: src/polymorphic/tests/examples/integrations/drf/migrations/0001_initial.py
class Migration (line 8) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/integrations/drf/models/example_models.py
class Project (line 6) | class Project(PolymorphicModel):
class ArtProject (line 10) | class ArtProject(Project):
class ResearchProject (line 14) | class ResearchProject(Project):
FILE: src/polymorphic/tests/examples/integrations/drf/models/filters.py
class Annotator (line 10) | class Annotator(PolymorphicModel):
class UserAnnotator (line 14) | class UserAnnotator(Annotator):
class AiModelAnnotator (line 20) | class AiModelAnnotator(Annotator):
class Data (line 25) | class Data(models.Model):
FILE: src/polymorphic/tests/examples/integrations/drf/models/models_test.py
class BlogBase (line 6) | class BlogBase(PolymorphicModel):
class BlogOne (line 11) | class BlogOne(BlogBase):
class BlogTwo (line 15) | class BlogTwo(BlogBase):
class BlogThree (line 19) | class BlogThree(BlogBase):
class Meta (line 23) | class Meta:
FILE: src/polymorphic/tests/examples/integrations/drf/serializers.py
class BlogBaseSerializer (line 8) | class BlogBaseSerializer(serializers.ModelSerializer):
class Meta (line 9) | class Meta:
class BlogOneSerializer (line 14) | class BlogOneSerializer(serializers.ModelSerializer):
class Meta (line 15) | class Meta:
class BlogTwoSerializer (line 20) | class BlogTwoSerializer(serializers.ModelSerializer):
class Meta (line 21) | class Meta:
class BlogThreeSerializer (line 26) | class BlogThreeSerializer(serializers.ModelSerializer):
class Meta (line 27) | class Meta:
class BlogPolymorphicSerializer (line 32) | class BlogPolymorphicSerializer(PolymorphicSerializer):
FILE: src/polymorphic/tests/examples/integrations/drf/test.py
class TestPolymorphicSerializer (line 31) | class TestPolymorphicSerializer:
method test_model_serializer_mapping_is_none (line 32) | def test_model_serializer_mapping_is_none(self):
method test_resource_type_field_name_is_not_string (line 44) | def test_resource_type_field_name_is_not_string(self, mocker):
method test_each_serializer_has_context (line 56) | def test_each_serializer_has_context(self, mocker):
method test_non_callable_serializer_in_mapping (line 62) | def test_non_callable_serializer_in_mapping(self):
method test_serialize (line 132) | def test_serialize(self):
method test_deserialize (line 141) | def test_deserialize(self):
method test_deserialize_with_invalid_resourcetype (line 151) | def test_deserialize_with_invalid_resourcetype(self):
method test_create (line 159) | def test_create(self):
method test_update (line 183) | def test_update(self):
method test_partial_update (line 198) | def test_partial_update(self):
method test_partial_update_without_resourcetype (line 211) | def test_partial_update_without_resourcetype(self):
method test_object_validators_are_applied (line 224) | def test_object_validators_are_applied(self):
method test_to_internal_value_with_valid_data (line 245) | def test_to_internal_value_with_valid_data(self):
method test_to_internal_value_with_missing_resourcetype (line 258) | def test_to_internal_value_with_missing_resourcetype(self):
method test_to_internal_value_with_partial_update (line 273) | def test_to_internal_value_with_partial_update(self):
method test_get_serializer_from_model_or_instance_raises_keyerror (line 285) | def test_get_serializer_from_model_or_instance_raises_keyerror(self):
method test_get_serializer_from_resource_type_keyerror_propagation (line 301) | def test_get_serializer_from_resource_type_keyerror_propagation(self):
method test_validate_method_modifications_are_preserved (line 333) | def test_validate_method_modifications_are_preserved(self):
class TestProjectViewSet (line 399) | class TestProjectViewSet:
method client (line 403) | def client(self):
method base_project (line 407) | def base_project(self):
method art_project (line 411) | def art_project(self):
method research_project (line 415) | def research_project(self):
method test_list_projects (line 420) | def test_list_projects(
method test_retrieve_base_project (line 430) | def test_retrieve_base_project(self, client, base_project):
method test_retrieve_art_project (line 438) | def test_retrieve_art_project(self, client, art_project):
method test_retrieve_research_project (line 448) | def test_retrieve_research_project(self, client, research_project):
method test_create_base_project (line 457) | def test_create_base_project(self, client):
method test_create_art_project (line 471) | def test_create_art_project(self, client):
method test_create_research_project (line 491) | def test_create_research_project(self, client):
method test_update_project (line 510) | def test_update_project(self, client, base_project):
method test_partial_update_art_project (line 523) | def test_partial_update_art_project(self, client, art_project):
method test_partial_update_research_project (line 538) | def test_partial_update_research_project(self, client, research_project):
method test_delete_project (line 553) | def test_delete_project(self, client, base_project):
method test_create_with_invalid_resourcetype (line 562) | def test_create_with_invalid_resourcetype(self, client):
class TestDjangoFiltersViewSet (line 570) | class TestDjangoFiltersViewSet:
method client (line 574) | def client(self):
method user (line 578) | def user(self, django_user_model):
method user_annotator (line 584) | def user_annotator(self, user):
method ai_annotator_gpt4 (line 590) | def ai_annotator_gpt4(self):
method ai_annotator_claude (line 596) | def ai_annotator_claude(self):
method data_by_user (line 604) | def data_by_user(self, user_annotator):
method data_by_gpt4 (line 610) | def data_by_gpt4(self, ai_annotator_gpt4):
method data_by_claude (line 616) | def data_by_claude(self, ai_annotator_claude):
method test_list_all_annotations (line 621) | def test_list_all_annotations(
method test_filter_by_annotator (line 629) | def test_filter_by_annotator(
method test_filter_by_ai_model (line 640) | def test_filter_by_ai_model(
method test_filter_by_different_ai_model (line 652) | def test_filter_by_different_ai_model(
method test_filter_by_nonexistent_ai_model (line 663) | def test_filter_by_nonexistent_ai_model(
method test_filter_excludes_non_ai_annotators (line 673) | def test_filter_excludes_non_ai_annotators(
method test_retrieve_annotation (line 687) | def test_retrieve_annotation(self, client, data_by_gpt4):
method test_create_annotation_with_user_annotator (line 695) | def test_create_annotation_with_user_annotator(
method test_create_annotation_with_ai_annotator (line 712) | def test_create_annotation_with_ai_annotator(
FILE: src/polymorphic/tests/examples/integrations/drf/views.py
class ProjectViewSet (line 7) | class ProjectViewSet(viewsets.ModelViewSet):
FILE: src/polymorphic/tests/examples/integrations/extra_views/apps.py
class ExtraViewsExampleConfig (line 4) | class ExtraViewsExampleConfig(AppConfig):
FILE: src/polymorphic/tests/examples/integrations/extra_views/templatetags/extra_views_tags.py
function model_name (line 7) | def model_name(instance):
FILE: src/polymorphic/tests/examples/integrations/extra_views/test.py
class ExtraViewsIntegrationTests (line 19) | class ExtraViewsIntegrationTests(TestCase):
method test_formset_children_configuration (line 29) | def test_formset_children_configuration(self):
method test_formset_generation (line 40) | def test_formset_generation(self):
method test_formset_with_existing_objects (line 53) | def test_formset_with_existing_objects(self):
method test_formset_extra_forms_configuration (line 79) | def test_formset_extra_forms_configuration(self):
method test_formset_saving_new_objects (line 102) | def test_formset_saving_new_objects(self):
method test_formset_updating_objects (line 154) | def test_formset_updating_objects(self):
method test_formset_deleting_objects (line 198) | def test_formset_deleting_objects(self):
method test_formset_mixed_operations (line 239) | def test_formset_mixed_operations(self):
class ExtraViewsUITests (line 319) | class ExtraViewsUITests(TestCase):
method test_formset_view_get_request (line 322) | def test_formset_view_get_request(self):
method test_formset_view_post_request (line 346) | def test_formset_view_post_request(self):
class ExtraViewsLiveServerTests (line 383) | class ExtraViewsLiveServerTests(_GenericUITest):
method setUp (line 386) | def setUp(self):
method tearDown (line 390) | def tearDown(self):
method test_formset_view_renders_existing_objects (line 395) | def test_formset_view_renders_existing_objects(self):
method test_formset_update_existing_object (line 429) | def test_formset_update_existing_object(self):
method test_formset_delete_existing_object (line 465) | def test_formset_delete_existing_object(self):
method test_formset_displays_multiple_polymorphic_types (line 499) | def test_formset_displays_multiple_polymorphic_types(self):
method test_formset_mixed_operations_through_ui (line 531) | def test_formset_mixed_operations_through_ui(self):
method test_formset_empty_state_shows_extra_forms (line 579) | def test_formset_empty_state_shows_extra_forms(self):
method test_formset_create_new_objects_via_extra_forms (line 617) | def test_formset_create_new_objects_via_extra_forms(self):
FILE: src/polymorphic/tests/examples/integrations/extra_views/views.py
class ArticleFormSetView (line 7) | class ArticleFormSetView(PolymorphicFormSetView):
FILE: src/polymorphic/tests/examples/integrations/guardian/apps.py
class GuardianExampleConfig (line 4) | class GuardianExampleConfig(AppConfig):
FILE: src/polymorphic/tests/examples/integrations/guardian/test.py
class GuardianIntegrationTests (line 22) | class GuardianIntegrationTests(TestCase):
method setUp (line 36) | def setUp(self):
method test_non_polymorphic_model (line 48) | def test_non_polymorphic_model(self):
method test_get_polymorphic_base_content_type_for_child_model (line 57) | def test_get_polymorphic_base_content_type_for_child_model(self):
method test_get_polymorphic_base_content_type_for_different_child_models (line 70) | def test_get_polymorphic_base_content_type_for_different_child_models(
method test_get_polymorphic_base_content_type_for_base_model (line 81) | def test_get_polymorphic_base_content_type_for_base_model(self):
method test_get_polymorphic_base_content_type_for_non_polymorphic_model (line 94) | def test_get_polymorphic_base_content_type_for_non_polymorphic_model(
method test_get_polymorphic_base_content_type_with_model_class (line 103) | def test_get_polymorphic_base_content_type_with_model_class(self):
method test_content_type_consistency_across_inheritance_chain (line 113) | def test_content_type_consistency_across_inheritance_chain(self):
method test_get_polymorphic_base_content_type_with_instance_and_class (line 126) | def test_get_polymorphic_base_content_type_with_instance_and_class(
method test_get_polymorphic_base_content_type_returns_content_type_object (line 140) | def test_get_polymorphic_base_content_type_returns_content_type_object(
method test_guardian_permissions_use_base_model_namespace (line 148) | def test_guardian_permissions_use_base_model_namespace(self):
FILE: src/polymorphic/tests/examples/integrations/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/integrations/models.py
class Article (line 5) | class Article(PolymorphicModel):
method __str__ (line 10) | def __str__(self):
class BlogPost (line 14) | class BlogPost(Article):
class NewsArticle (line 18) | class NewsArticle(Article):
FILE: src/polymorphic/tests/examples/integrations/reversion/admin.py
class ArticleChildAdmin (line 10) | class ArticleChildAdmin(PolymorphicChildModelAdmin, VersionAdmin):
class BlogPostAdmin (line 15) | class BlogPostAdmin(ArticleChildAdmin):
class NewsArticleAdmin (line 20) | class NewsArticleAdmin(ArticleChildAdmin):
class ArticleParentAdmin (line 24) | class ArticleParentAdmin(VersionAdmin, PolymorphicParentModelAdmin):
FILE: src/polymorphic/tests/examples/integrations/reversion/apps.py
class ReversionExampleConfig (line 4) | class ReversionExampleConfig(AppConfig):
FILE: src/polymorphic/tests/examples/integrations/reversion/test.py
class ReversionIntegrationTests (line 21) | class ReversionIntegrationTests(TestCase):
method test_blogpost_versioning (line 31) | def test_blogpost_versioning(self):
method test_newsarticle_versioning (line 64) | def test_newsarticle_versioning(self):
method test_polymorphic_queryset_with_versioned_objects (line 89) | def test_polymorphic_queryset_with_versioned_objects(self):
method test_revert_to_previous_version (line 117) | def test_revert_to_previous_version(self):
method test_manual_reversion_workflow (line 154) | def test_manual_reversion_workflow(self):
method test_manual_newsarticle_reversion_with_deletion (line 226) | def test_manual_newsarticle_reversion_with_deletion(self):
method test_manual_batch_reversion (line 269) | def test_manual_batch_reversion(self):
class ReversionAdminUITests (line 321) | class ReversionAdminUITests(_GenericUITest):
method test_blogpost_admin_reversion (line 324) | def test_blogpost_admin_reversion(self):
method test_article_admin_reversion (line 433) | def test_article_admin_reversion(self):
method test_newsarticle_admin_reversion (line 505) | def test_newsarticle_admin_reversion(self):
FILE: src/polymorphic/tests/examples/type_hints/fk/apps.py
class TypeHintsFKConfig (line 4) | class TypeHintsFKConfig(AppConfig):
FILE: src/polymorphic/tests/examples/type_hints/fk/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/type_hints/fk/models.py
class ParentModel (line 10) | class ParentModel(PolymorphicModel):
class Child1 (line 16) | class Child1(ParentModel):
class Child2 (line 20) | class Child2(Child1):
class RelatedModel (line 24) | class RelatedModel(models.Model):
FILE: src/polymorphic/tests/examples/type_hints/fk/test.py
class TypeHintsFKTest (line 7) | class TypeHintsFKTest(TestCase):
method test_type_hints (line 8) | def test_type_hints(self):
FILE: src/polymorphic/tests/examples/type_hints/m2m/apps.py
class TypeHintsM2MConfig (line 4) | class TypeHintsM2MConfig(AppConfig):
FILE: src/polymorphic/tests/examples/type_hints/m2m/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/type_hints/m2m/models.py
class ParentModel (line 13) | class ParentModel(PolymorphicModel):
class Child1 (line 27) | class Child1(ParentModel):
class Child2 (line 31) | class Child2(Child1):
class PolyThrough (line 35) | class PolyThrough(PolymorphicModel):
class ThroughChild (line 49) | class ThroughChild(PolyThrough):
class RelatedModel (line 53) | class RelatedModel(models.Model):
FILE: src/polymorphic/tests/examples/type_hints/m2m/test.py
class TypeHintsM2MTest (line 16) | class TypeHintsM2MTest(TestCase):
method test_type_hints (line 17) | def test_type_hints(self):
FILE: src/polymorphic/tests/examples/type_hints/managers/apps.py
class TypeHintsManagersConfig (line 4) | class TypeHintsManagersConfig(AppConfig):
FILE: src/polymorphic/tests/examples/type_hints/managers/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/type_hints/managers/models.py
class ParentModel (line 8) | class ParentModel(PolymorphicModel):
class Child1 (line 21) | class Child1(ParentModel):
class Child2 (line 27) | class Child2(Child1):
FILE: src/polymorphic/tests/examples/type_hints/managers/test.py
class TypeHintsManagersTest (line 6) | class TypeHintsManagersTest(TestCase):
method test_type_hints (line 7) | def test_type_hints(self):
FILE: src/polymorphic/tests/examples/type_hints/one2one/apps.py
class TypeHintsOne2OneConfig (line 4) | class TypeHintsOne2OneConfig(AppConfig):
FILE: src/polymorphic/tests/examples/type_hints/one2one/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/type_hints/one2one/models.py
class ParentModel (line 10) | class ParentModel(PolymorphicModel):
class Child1 (line 16) | class Child1(ParentModel):
class Child2 (line 20) | class Child2(Child1):
class RelatedModel (line 24) | class RelatedModel(models.Model):
FILE: src/polymorphic/tests/examples/type_hints/one2one/test.py
class TypeHintsOne2OneTest (line 11) | class TypeHintsOne2OneTest(TestCase):
method test_type_hints (line 12) | def test_type_hints(self):
FILE: src/polymorphic/tests/examples/views/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/examples/views/models.py
class Project (line 5) | class Project(PolymorphicModel):
class ArtProject (line 9) | class ArtProject(Project):
class ResearchProject (line 13) | class ResearchProject(Project):
FILE: src/polymorphic/tests/examples/views/test.py
class ViewExampleTests (line 8) | class ViewExampleTests(_GenericUITest):
method test_view_example (line 9) | def test_view_example(self):
FILE: src/polymorphic/tests/examples/views/views.py
class ProjectTypeChoiceForm (line 11) | class ProjectTypeChoiceForm(forms.Form):
class ProjectTypeSelectView (line 18) | class ProjectTypeSelectView(FormView):
method get_form_kwargs (line 22) | def get_form_kwargs(self):
method get_form (line 32) | def get_form(self, form_class=None):
method form_valid (line 42) | def form_valid(self, form):
class ProjectCreateView (line 47) | class ProjectCreateView(CreateView):
method get_success_url (line 51) | def get_success_url(self):
method get_form_class (line 54) | def get_form_class(self):
method get_context_data (line 73) | def get_context_data(self, **kwargs):
FILE: src/polymorphic/tests/migrations/0001_initial.py
class Migration (line 12) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/models.py
class PlainA (line 19) | class PlainA(models.Model):
method __str__ (line 22) | def __str__(self):
class PlainB (line 26) | class PlainB(PlainA):
class PlainC (line 30) | class PlainC(PlainB):
class PlainD (line 34) | class PlainD(PlainA):
class Model2A (line 38) | class Model2A(ShowFieldType, PolymorphicModel):
class RandomMixinB (line 43) | class RandomMixinB:
method random_method (line 44) | def random_method(self):
class Model2B (line 48) | class Model2B(RandomMixinB, Model2A):
class RandomMixinC (line 52) | class RandomMixinC:
method random_method (line 53) | def random_method(self):
class Model2C (line 57) | class Model2C(RandomMixinC, Model2B):
class Model2D (line 61) | class Model2D(Model2C):
class ModelExtraA (line 65) | class ModelExtraA(ShowFieldTypeAndContent, PolymorphicModel):
class ModelExtraB (line 69) | class ModelExtraB(ModelExtraA):
class ModelExtraC (line 73) | class ModelExtraC(ModelExtraB):
class ModelExtraExternal (line 77) | class ModelExtraExternal(models.Model):
class ModelShow1 (line 81) | class ModelShow1(ShowFieldType, PolymorphicModel):
class ModelShow2 (line 86) | class ModelShow2(ShowFieldContent, PolymorphicModel):
class ModelShow3 (line 91) | class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel):
class ModelShow1_plain (line 96) | class ModelShow1_plain(PolymorphicModel):
class ModelShow2_plain (line 100) | class ModelShow2_plain(ModelShow1_plain):
class Base (line 104) | class Base(ShowFieldType, PolymorphicModel):
class ModelX (line 109) | class ModelX(Base):
class ModelY (line 113) | class ModelY(Base):
class Enhance_Plain (line 117) | class Enhance_Plain(models.Model):
class Enhance_Base (line 121) | class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel):
class Enhance_Inherit (line 126) | class Enhance_Inherit(Enhance_Base, Enhance_Plain):
class RelationAbstractModel (line 130) | class RelationAbstractModel(models.Model):
class Meta (line 131) | class Meta:
class RelationBase (line 135) | class RelationBase(RelationAbstractModel, ShowFieldTypeAndContent, Polym...
class RelationA (line 143) | class RelationA(RelationBase):
class RelationB (line 147) | class RelationB(RelationBase):
class RelationBC (line 151) | class RelationBC(RelationB):
class RelatingModel (line 155) | class RelatingModel(models.Model):
class One2OneRelatingModel (line 159) | class One2OneRelatingModel(PolymorphicModel):
class One2OneRelatingModelDerived (line 164) | class One2OneRelatingModelDerived(One2OneRelatingModel):
class ModelUnderRelParent (line 168) | class ModelUnderRelParent(PolymorphicModel):
class ModelUnderRelChild (line 173) | class ModelUnderRelChild(PolymorphicModel):
class MyManagerQuerySet (line 180) | class MyManagerQuerySet(PolymorphicQuerySet):
method my_queryset_foo (line 181) | def my_queryset_foo(self):
class MyManager (line 186) | class MyManager(PolymorphicManager):
method get_queryset (line 189) | def get_queryset(self):
method my_queryset_foo (line 192) | def my_queryset_foo(self):
class ModelWithMyManager (line 196) | class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
class ModelWithMyManagerNoDefault (line 201) | class ModelWithMyManagerNoDefault(ShowFieldTypeAndContent, Model2A):
class ModelWithMyManagerDefault (line 207) | class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A):
class ModelWithMyManager2 (line 213) | class ModelWithMyManager2(ShowFieldTypeAndContent, Model2A):
class ModelArticle (line 218) | class ModelArticle(PolymorphicModel):
class ModelPackage (line 222) | class ModelPackage(ModelArticle):
class ModelComponent (line 226) | class ModelComponent(ModelArticle):
class ModelOrderLine (line 230) | class ModelOrderLine(models.Model):
class MROBase1 (line 234) | class MROBase1(ShowFieldType, PolymorphicModel):
class MROBase2 (line 239) | class MROBase2(MROBase1):
class MROBase3 (line 244) | class MROBase3(models.Model):
class MRODerived (line 250) | class MRODerived(MROBase2, MROBase3):
class ParentModelWithManager (line 254) | class ParentModelWithManager(PolymorphicModel):
class ChildModelWithManager (line 258) | class ChildModelWithManager(PolymorphicModel):
class PlainMyManagerQuerySet (line 267) | class PlainMyManagerQuerySet(QuerySet):
method my_queryset_foo (line 268) | def my_queryset_foo(self):
class PlainMyManager (line 273) | class PlainMyManager(models.Manager):
method my_queryset_foo (line 274) | def my_queryset_foo(self):
method get_queryset (line 277) | def get_queryset(self):
class PlainParentModelWithManager (line 281) | class PlainParentModelWithManager(models.Model):
class PlainChildModelWithManager (line 285) | class PlainChildModelWithManager(models.Model):
class BlogBase (line 294) | class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
class BlogA (line 298) | class BlogA(BlogBase):
class BlogB (line 302) | class BlogB(BlogBase):
class BlogEntry (line 306) | class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
class BlogEntry_limit_choices_to (line 311) | class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicMod...
class ModelFieldNameTest (line 316) | class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
class InitTestModel (line 320) | class InitTestModel(ShowFieldType, PolymorphicModel):
method __init__ (line 323) | def __init__(self, *args, **kwargs):
class InitTestModelSubclass (line 328) | class InitTestModelSubclass(InitTestModel):
method x (line 329) | def x(self):
class Top (line 336) | class Top(PolymorphicModel):
class Middle (line 340) | class Middle(Top):
class Bottom (line 344) | class Bottom(Middle):
class UUIDProject (line 348) | class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
class UUIDArtProject (line 353) | class UUIDArtProject(UUIDProject):
class UUIDResearchProject (line 357) | class UUIDResearchProject(UUIDProject):
class UUIDArtProjectA (line 361) | class UUIDArtProjectA(UUIDArtProject): ...
class UUIDArtProjectB (line 364) | class UUIDArtProjectB(UUIDArtProjectA): ...
class UUIDArtProjectC (line 367) | class UUIDArtProjectC(UUIDArtProjectB): ...
class UUIDArtProjectD (line 370) | class UUIDArtProjectD(UUIDArtProjectC): ...
class UUIDPlainA (line 373) | class UUIDPlainA(models.Model):
class UUIDPlainB (line 378) | class UUIDPlainB(UUIDPlainA):
class UUIDPlainC (line 382) | class UUIDPlainC(UUIDPlainB):
class ProxyBase (line 389) | class ProxyBase(PolymorphicModel):
class ProxyChild (line 393) | class ProxyChild(ProxyBase):
class Meta (line 394) | class Meta:
class NonProxyChild (line 398) | class NonProxyChild(ProxyBase):
class ProxiedBase (line 405) | class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel):
class ProxyModelBase (line 409) | class ProxyModelBase(ProxiedBase):
class Meta (line 410) | class Meta:
class ProxyModelA (line 414) | class ProxyModelA(ProxyModelBase):
class ProxyModelB (line 418) | class ProxyModelB(ProxyModelBase):
class RelatedNameClash (line 430) | class RelatedNameClash(ShowFieldType, PolymorphicModel):
class ParentLinkAndRelatedName (line 437) | class ParentLinkAndRelatedName(ModelShow1_plain):
class CustomPkBase (line 446) | class CustomPkBase(ShowFieldTypeAndContent, PolymorphicModel):
class CustomPkInherit (line 450) | class CustomPkInherit(CustomPkBase):
class DateModel (line 455) | class DateModel(PolymorphicModel):
class AbstractModel (line 461) | class AbstractModel(PolymorphicModel):
class Meta (line 462) | class Meta:
class SwappableModel (line 466) | class SwappableModel(AbstractModel):
class Meta (line 467) | class Meta:
class SwappedModel (line 471) | class SwappedModel(AbstractModel):
class InlineParent (line 475) | class InlineParent(models.Model):
class InlineModelA (line 479) | class InlineModelA(PolymorphicModel):
class InlineModelB (line 486) | class InlineModelB(InlineModelA):
class AbstractProject (line 502) | class AbstractProject(PolymorphicModel):
class Meta (line 505) | class Meta:
class ArtProject (line 509) | class ArtProject(AbstractProject):
class Duck (line 513) | class Duck(PolymorphicModel):
class RedheadDuck (line 517) | class RedheadDuck(Duck):
class Meta (line 518) | class Meta:
class RubberDuck (line 522) | class RubberDuck(Duck):
class Meta (line 523) | class Meta:
class MultiTableBase (line 527) | class MultiTableBase(PolymorphicModel):
class MultiTableDerived (line 531) | class MultiTableDerived(MultiTableBase):
class SubclassSelectorAbstractBaseModel (line 535) | class SubclassSelectorAbstractBaseModel(PolymorphicModel):
class SubclassSelectorAbstractModel (line 539) | class SubclassSelectorAbstractModel(SubclassSelectorAbstractBaseModel):
class Meta (line 542) | class Meta:
class SubclassSelectorAbstractConcreteModel (line 546) | class SubclassSelectorAbstractConcreteModel(SubclassSelectorAbstractModel):
class SubclassSelectorProxyBaseModel (line 550) | class SubclassSelectorProxyBaseModel(PolymorphicModel):
class SubclassSelectorProxyModel (line 554) | class SubclassSelectorProxyModel(SubclassSelectorProxyBaseModel):
class Meta (line 555) | class Meta:
class SubclassSelectorProxyConcreteModel (line 559) | class SubclassSelectorProxyConcreteModel(SubclassSelectorProxyModel):
class NonPolymorphicParent (line 563) | class NonPolymorphicParent(PolymorphicModel, Group):
class Participant (line 567) | class Participant(PolymorphicModel):
class UserProfile (line 571) | class UserProfile(Participant):
method __str__ (line 574) | def __str__(self):
class Team (line 578) | class Team(models.Model):
class BlueHeadDuck (line 583) | class BlueHeadDuck(Duck):
method __init__ (line 584) | def __init__(self, *args, **kwargs):
class HomeDuck (line 589) | class HomeDuck(models.Model):
method __init__ (line 590) | def __init__(self, *args, **kwargs):
class Meta (line 594) | class Meta:
class PurpleHeadDuck (line 598) | class PurpleHeadDuck(HomeDuck, BlueHeadDuck):
class Meta (line 599) | class Meta:
class Account (line 603) | class Account(PolymorphicModel):
class SpecialAccount1 (line 609) | class SpecialAccount1(Account):
class SpecialAccount1_1 (line 613) | class SpecialAccount1_1(SpecialAccount1):
class SpecialAccount2 (line 617) | class SpecialAccount2(Account):
class ModelMixin (line 621) | class ModelMixin(models.Model):
class Meta (line 622) | class Meta:
class PolymorphicMixin (line 629) | class PolymorphicMixin(PolymorphicModel):
class Meta (line 630) | class Meta:
class Foo (line 637) | class Foo(PolymorphicModel):
class Bar (line 641) | class Bar(PolymorphicMixin, PolymorphicModel):
class Baz (line 645) | class Baz(ModelMixin, PolymorphicModel):
class MyBaseQuerySet (line 649) | class MyBaseQuerySet(PolymorphicQuerySet):
method filter_by_user (line 650) | def filter_by_user(self, _):
class MyBaseModel (line 654) | class MyBaseModel(PolymorphicModel):
class MyChild1QuerySet (line 659) | class MyChild1QuerySet(MyBaseQuerySet):
method filter_by_user (line 660) | def filter_by_user(self, num):
class MyChild1Model (line 664) | class MyChild1Model(MyBaseModel):
class MyChild2QuerySet (line 670) | class MyChild2QuerySet(MyBaseQuerySet):
method filter_by_user (line 671) | def filter_by_user(self, num):
class MyChild2Model (line 675) | class MyChild2Model(MyBaseModel):
class SpecialQuerySet (line 682) | class SpecialQuerySet(PolymorphicQuerySet):
method has_text (line 683) | def has_text(self, text):
class SpecialPolymorphicManager (line 687) | class SpecialPolymorphicManager(PolymorphicManager.from_queryset(Special...
method custom_queryset (line 688) | def custom_queryset(self):
class AbstractManagerTest (line 692) | class AbstractManagerTest(PolymorphicModel):
class Meta (line 703) | class Meta:
class RelatedManagerTest (line 707) | class RelatedManagerTest(models.Model): ...
class DerivedManagerTest (line 710) | class DerivedManagerTest(AbstractManagerTest):
class DerivedManagerTest2 (line 720) | class DerivedManagerTest2(DerivedManagerTest):
class FKTestBase (line 724) | class FKTestBase(PolymorphicModel): ...
class FKTestChild (line 727) | class FKTestChild(Base): ...
class FKTest (line 730) | class FKTest(models.Model):
class NoChildren (line 734) | class NoChildren(PolymorphicModel):
class ModelWithPolyFK (line 738) | class ModelWithPolyFK(models.Model):
class NormalBase (line 745) | class NormalBase(models.Model):
method add_to_nb (line 748) | def add_to_nb(self, value):
class NormalExtension (line 753) | class NormalExtension(NormalBase):
method add_to_ne (line 756) | def add_to_ne(self, value):
class PolyExtension (line 761) | class PolyExtension(PolymorphicModel, NormalExtension):
method add_to_ext (line 764) | def add_to_ext(self, value):
class PolyExtChild (line 769) | class PolyExtChild(PolyExtension):
method add_to_child (line 772) | def add_to_child(self, value):
method override_add_to_ne (line 776) | def override_add_to_ne(self, value):
method override_add_to_ext (line 781) | def override_add_to_ext(self, value):
class DeepCopyTester (line 787) | class DeepCopyTester(PolymorphicModel):
class DeepCopyTester2 (line 791) | class DeepCopyTester2(DeepCopyTester):
class DucksLake (line 795) | class DucksLake(models.Model):
class Lake (line 801) | class Lake(models.Model):
class LakeWithThrough (line 805) | class LakeWithThrough(models.Model):
class ChoiceBlank (line 809) | class ChoiceBlank(PolymorphicModel):
class ChoiceAthlete (line 813) | class ChoiceAthlete(ChoiceBlank):
class BetMultiple (line 817) | class BetMultiple(models.Model):
class RankedAthlete (line 821) | class RankedAthlete(models.Model):
class RecursionBug (line 827) | class RecursionBug(PolymorphicModel):
method __init__ (line 830) | def __init__(self, *args, **kwargs):
class TaggedItem (line 838) | class TaggedItem(models.Model):
class BookmarkManager (line 845) | class BookmarkManager(PolymorphicManager):
method get_queryset (line 846) | def get_queryset(self) -> PolymorphicQuerySet:
class Bookmark (line 850) | class Bookmark(PolymorphicModel):
class Assignment (line 856) | class Assignment(Bookmark):
class Regression295Related (line 860) | class Regression295Related(models.Model):
class Regression295Parent (line 864) | class Regression295Parent(PolymorphicModel):
class RelatedKeyModel (line 868) | class RelatedKeyModel(models.Model):
class DisparateKeysParent (line 872) | class DisparateKeysParent(PolymorphicModel):
class DisparateKeysChild1 (line 876) | class DisparateKeysChild1(DisparateKeysParent):
class DisparateKeysChild2 (line 882) | class DisparateKeysChild2(DisparateKeysParent):
class DisparateKeysGrandChild2 (line 887) | class DisparateKeysGrandChild2(DisparateKeysChild2):
class DisparateKeysGrandChild (line 891) | class DisparateKeysGrandChild(DisparateKeysChild1):
class M2MAdminTest (line 895) | class M2MAdminTest(PolymorphicModel):
method __str__ (line 898) | def __str__(self):
class M2MAdminTestChildA (line 902) | class M2MAdminTestChildA(M2MAdminTest):
class M2MAdminTestChildB (line 906) | class M2MAdminTestChildB(M2MAdminTest):
class M2MAdminTestChildC (line 910) | class M2MAdminTestChildC(M2MAdminTestChildB):
class M2MThroughBase (line 915) | class M2MThroughBase(PolymorphicModel):
method __str__ (line 920) | def __str__(self):
class M2MThroughPerson (line 924) | class M2MThroughPerson(M2MThroughBase):
class M2MThroughSpecialPerson (line 930) | class M2MThroughSpecialPerson(M2MThroughPerson):
class M2MThroughProject (line 936) | class M2MThroughProject(M2MThroughBase):
class M2MThroughProjectWithTeam (line 942) | class M2MThroughProjectWithTeam(M2MThroughProject):
class M2MThroughMembership (line 951) | class M2MThroughMembership(PolymorphicModel):
method __str__ (line 959) | def __str__(self):
class M2MThroughMembershipWithPerson (line 963) | class M2MThroughMembershipWithPerson(M2MThroughMembership):
class M2MThroughMembershipWithSpecialPerson (line 969) | class M2MThroughMembershipWithSpecialPerson(M2MThroughMembership):
class DirectM2MContainer (line 985) | class DirectM2MContainer(models.Model):
method __str__ (line 991) | def __str__(self):
class Author (line 995) | class Author(models.Model):
class Book (line 999) | class Book(PolymorphicModel):
class SpecialBook (line 1003) | class SpecialBook(Book):
class FilteredManager (line 1007) | class FilteredManager(PolymorphicManager):
method get_queryset (line 1008) | def get_queryset(self):
class Model2BFiltered (line 1012) | class Model2BFiltered(Model2B):
class Model2CFiltered (line 1016) | class Model2CFiltered(Model2BFiltered):
class CustomBaseManager (line 1020) | class CustomBaseManager(PolymorphicManager):
class FilteredManager2 (line 1024) | class FilteredManager2(FilteredManager):
class Model2CNamedManagers (line 1028) | class Model2CNamedManagers(Model2CFiltered):
class Meta (line 1032) | class Meta:
class Model2CNamedDefault (line 1037) | class Model2CNamedDefault(Model2CFiltered):
class Meta (line 1040) | class Meta:
class NatKeyManager (line 1045) | class NatKeyManager(PolymorphicManager):
method get_by_natural_key (line 1046) | def get_by_natural_key(self, slug):
class NatKeyParent (line 1050) | class NatKeyParent(PolymorphicModel):
method natural_key (line 1056) | def natural_key(self):
class NatKeyChild (line 1060) | class NatKeyChild(NatKeyParent):
method natural_key (line 1064) | def natural_key(self):
class ManagerTest (line 1070) | class ManagerTest(PolymorphicModel):
class Meta (line 1075) | class Meta:
class ManagerTestChild (line 1079) | class ManagerTestChild(ManagerTest):
class PlainManager (line 1083) | class PlainManager(models.Manager): ...
class ManagerTestPlain (line 1086) | class ManagerTestPlain(models.Model):
class Meta (line 1089) | class Meta:
class ManagerTestChildPlain (line 1093) | class ManagerTestChildPlain(ManagerTestPlain):
class GenericFKParent (line 1098) | class GenericFKParent(models.Model):
method __str__ (line 1103) | def __str__(self):
class PolymorphicTagBase (line 1107) | class PolymorphicTagBase(PolymorphicModel):
method __str__ (line 1115) | def __str__(self):
class PolymorphicTagA (line 1119) | class PolymorphicTagA(PolymorphicTagBase):
class PolymorphicTagB (line 1125) | class PolymorphicTagB(PolymorphicTagBase):
FILE: src/polymorphic/tests/other/migrations/0001_initial.py
class Migration (line 7) | class Migration(migrations.Migration):
FILE: src/polymorphic/tests/other/models.py
class UserProfile (line 5) | class UserProfile(Participant):
method __str__ (line 11) | def __str__(self):
FILE: src/polymorphic/tests/other/test_cross_apps.py
class TestCrossAppSubclasses (line 5) | class TestCrossAppSubclasses(TestCase):
method test_samename_different_app_subclasses (line 6) | def test_samename_different_app_subclasses(self):
FILE: src/polymorphic/tests/test_admin.py
class FileFieldInlineA (line 42) | class FileFieldInlineA(StackedPolymorphicInline.Child):
class FileFieldInlineB (line 46) | class FileFieldInlineB(StackedPolymorphicInline.Child):
class FileFieldInline (line 50) | class FileFieldInline(StackedPolymorphicInline):
class FileFieldParentAdmin (line 55) | class FileFieldParentAdmin(PolymorphicInlineSupportMixin, admin.ModelAdm...
class PolymorphicAdminTests (line 59) | class PolymorphicAdminTests(AdminTestCase):
method test_admin_registration (line 60) | def test_admin_registration(self):
method test_get_child_inlines (line 121) | def test_get_child_inlines(self):
method test_show_in_index (line 130) | def test_show_in_index(self):
method test_show_in_index_custom_site (line 182) | def test_show_in_index_custom_site(self):
method test_get_model_perms_hidden (line 220) | def test_get_model_perms_hidden(self):
method test_admin_inlines (line 242) | def test_admin_inlines(self):
method test_render_change_form_sets_has_file_field (line 299) | def test_render_change_form_sets_has_file_field(self):
class _GenericAdminFormTest (line 336) | class _GenericAdminFormTest(_GenericUITest):
method admin_url (line 339) | def admin_url(self):
method add_url (line 342) | def add_url(self, model):
method change_url (line 346) | def change_url(self, model, id):
method list_url (line 353) | def list_url(self, model):
method get_object_ids (line 357) | def get_object_ids(self, model):
class StackedInlineTests (line 364) | class StackedInlineTests(_GenericAdminFormTest):
method test_admin_inline_add_autocomplete (line 365) | def test_admin_inline_add_autocomplete(self):
method test_inline_form_ordering_and_removal (line 410) | def test_inline_form_ordering_and_removal(self):
method test_polymorphic_inline_file_upload (line 475) | def test_polymorphic_inline_file_upload(self):
class PolymorphicFormTests (line 577) | class PolymorphicFormTests(_GenericAdminFormTest):
method test_admin_polymorphic_add (line 578) | def test_admin_polymorphic_add(self):
method test_admin_popup_validation_error (line 653) | def test_admin_popup_validation_error(self):
class PolymorphicNoChildrenTests (line 751) | class PolymorphicNoChildrenTests(_GenericAdminFormTest):
method test_admin_no_polymorphic_children (line 752) | def test_admin_no_polymorphic_children(self):
class AdminRecentActionsTests (line 767) | class AdminRecentActionsTests(_GenericAdminFormTest):
method test_admin_recent_actions (line 768) | def test_admin_recent_actions(self):
class AdminPreservedFiltersTests (line 853) | class AdminPreservedFiltersTests(_GenericAdminFormTest):
method test_changelist_filter_persists_after_edit (line 854) | def test_changelist_filter_persists_after_edit(self):
class M2MAdminTests (line 913) | class M2MAdminTests(_GenericAdminFormTest):
method test_m2m_admin_raw_id_fields (line 914) | def test_m2m_admin_raw_id_fields(self):
method test_issue_182_m2m_field_to_polymorphic_model (line 1065) | def test_issue_182_m2m_field_to_polymorphic_model(self):
method test_issue_375_m2m_polymorphic_with_through_model (line 1184) | def test_issue_375_m2m_polymorphic_with_through_model(self):
class PolymorphicAdminCoverageTests (line 1339) | class PolymorphicAdminCoverageTests(AdminTestCase):
method test_get_child_models_not_implemented (line 1344) | def test_get_child_models_not_implemented(self):
method test_lazy_setup_old_format (line 1354) | def test_lazy_setup_old_format(self):
method test_get_real_admin_nonexistent_pk (line 1366) | def test_get_real_admin_nonexistent_pk(self):
method test_get_real_admin_by_ct_nonexistent (line 1384) | def test_get_real_admin_by_ct_nonexistent(self):
method test_get_real_admin_by_ct_deleted_model (line 1404) | def test_get_real_admin_by_ct_deleted_model(self):
method test_get_real_admin_by_model_permission_denied (line 1429) | def test_get_real_admin_by_model_permission_denied(self):
method test_child_admin_not_registered (line 1447) | def test_child_admin_not_registered(self):
method test_real_admin_is_self_returns_super (line 1466) | def test_real_admin_is_self_returns_super(self):
method test_get_queryset_polymorphic_list_true (line 1484) | def test_get_queryset_polymorphic_list_true(self):
method test_get_child_type_choices_skips_no_permission (line 1506) | def test_get_child_type_choices_skips_no_permission(self):
method test_add_type_view_no_add_permission (line 1536) | def test_add_type_view_no_add_permission(self):
method test_add_type_view_no_choices_permission_denied (line 1557) | def test_add_type_view_no_choices_permission_denied(self):
method test_child_admin_get_form_with_fieldsets (line 1580) | def test_child_admin_get_form_with_fieldsets(self):
method test_child_admin_get_parent_admin_self_is_parent (line 1599) | def test_child_admin_get_parent_admin_self_is_parent(self):
method test_child_admin_get_parent_admin_mro_scan (line 1613) | def test_child_admin_get_parent_admin_mro_scan(self):
method test_child_admin_get_parent_admin_not_registered (line 1632) | def test_child_admin_get_parent_admin_not_registered(self):
method test_child_admin_history_view_extra_context (line 1644) | def test_child_admin_history_view_extra_context(self):
method test_child_admin_get_fieldsets_no_subclass_fields (line 1662) | def test_child_admin_get_fieldsets_no_subclass_fields(self):
method test_child_admin_get_subclass_fields_with_tuple_field (line 1684) | def test_child_admin_get_subclass_fields_with_tuple_field(self):
method test_child_admin_get_subclass_fields_missing_field (line 1707) | def test_child_admin_get_subclass_fields_missing_field(self):
method test_filter_queryset_type_error (line 1729) | def test_filter_queryset_type_error(self):
method test_filter_queryset_permission_denied (line 1753) | def test_filter_queryset_permission_denied(self):
method test_inline_parent_not_in_registry_skips_check (line 1779) | def test_inline_parent_not_in_registry_skips_check(self):
method test_inline_improperly_configured_missing_mixin (line 1793) | def test_inline_improperly_configured_missing_mixin(self):
method test_inline_unsupported_child_type (line 1811) | def test_inline_unsupported_child_type(self):
method test_inline_get_fieldsets_with_fieldsets_set (line 1830) | def test_inline_get_fieldsets_with_fieldsets_set(self):
method test_inline_get_fieldsets_empty (line 1847) | def test_inline_get_fieldsets_empty(self):
method test_inline_get_fields_with_fields_set (line 1862) | def test_inline_get_fields_with_fields_set(self):
method test_inline_get_fields_no_fields_returns_empty (line 1878) | def test_inline_get_fields_no_fields_returns_empty(self):
method test_inline_child_get_formset_raises_runtime_error (line 1894) | def test_inline_child_get_formset_raises_runtime_error(self):
method test_inline_child_get_fields_with_fields_set (line 1914) | def test_inline_child_get_fields_with_fields_set(self):
method test_inline_child_exclude_in_formset (line 1934) | def test_inline_child_exclude_in_formset(self):
method test_inline_child_form_meta_exclude (line 1956) | def test_inline_child_form_meta_exclude(self):
method test_inline_media_different_child_media (line 1984) | def test_inline_media_different_child_media(self):
method test_inline_get_inline_formsets_non_polymorphic (line 2013) | def test_inline_get_inline_formsets_non_polymorphic(self):
method test_polymorphic_inline_admin_form_is_empty_false_no_prefix (line 2038) | def test_polymorphic_inline_admin_form_is_empty_false_no_prefix(self):
method test_polymorphic_inline_admin_formset_init (line 2048) | def test_polymorphic_inline_admin_formset_init(self):
method test_generic_polymorphic_inline_get_formset (line 2061) | def test_generic_polymorphic_inline_get_formset(self):
class ExistingInlineTests (line 2093) | class ExistingInlineTests(_GenericAdminFormTest):
method test_inline_change_form_with_existing_children (line 2099) | def test_inline_change_form_with_existing_children(self):
FILE: src/polymorphic/tests/test_base.py
class PrimaryKeyNameTest (line 19) | class PrimaryKeyNameTest(TestCase):
method test_polymorphic_primary_key_name_correctness (line 20) | def test_polymorphic_primary_key_name_correctness(self):
method test_multiple_inheritance_pk_name (line 54) | def test_multiple_inheritance_pk_name(self):
FILE: src/polymorphic/tests/test_contrib.py
class ContribTests (line 7) | class ContribTests(TestCase):
method test_contrib_guardian (line 12) | def test_contrib_guardian(self):
FILE: src/polymorphic/tests/test_formsets.py
class PolymorphicFormSetChildTest (line 32) | class PolymorphicFormSetChildTest(TestCase):
method test_content_type_property (line 35) | def test_content_type_property(self):
method test_extra_exclude_parameter (line 43) | def test_extra_exclude_parameter(self):
class PolymorphicModelFormSetTest (line 53) | class PolymorphicModelFormSetTest(TestCase):
method setUp (line 56) | def setUp(self):
method test_empty_form_property_raises_error (line 60) | def test_empty_form_property_raises_error(self):
method test_error_no_child_forms (line 72) | def test_error_no_child_forms(self):
method test_error_non_polymorphic_model (line 85) | def test_error_non_polymorphic_model(self):
method test_error_unsupported_child_type (line 99) | def test_error_unsupported_child_type(self):
method test_bound_formset_with_data (line 111) | def test_bound_formset_with_data(self):
method test_extra_forms_cycle_child_types (line 147) | def test_extra_forms_cycle_child_types(self):
method test_validation_error_missing_ctype (line 166) | def test_validation_error_missing_ctype(self):
method test_unsupported_child_in_bound_data (line 187) | def test_unsupported_child_in_bound_data(self):
method test_unbound_with_ctype_in_initial (line 210) | def test_unbound_with_ctype_in_initial(self):
method test_child_form_kwargs (line 229) | def test_child_form_kwargs(self):
method test_is_multipart_with_file_field (line 241) | def test_is_multipart_with_file_field(self):
method test_media_aggregation (line 261) | def test_media_aggregation(self):
class PolymorphicInlineFormSetTest (line 283) | class PolymorphicInlineFormSetTest(TestCase):
method test_inline_formset_factory (line 286) | def test_inline_formset_factory(self):
method test_inline_with_child_form_kwargs (line 304) | def test_inline_with_child_form_kwargs(self):
class GenericPolymorphicFormSetChildTest (line 320) | class GenericPolymorphicFormSetChildTest(TestCase):
method test_content_type_property (line 323) | def test_content_type_property(self):
method test_ct_field_fk_field_defaults (line 331) | def test_ct_field_fk_field_defaults(self):
method test_custom_ct_field_fk_field (line 337) | def test_custom_ct_field_fk_field(self):
method test_get_form_excludes_gfk_fields (line 345) | def test_get_form_excludes_gfk_fields(self):
method test_get_form_with_extra_exclude (line 358) | def test_get_form_with_extra_exclude(self):
method test_get_form_invalid_ct_field_raises (line 370) | def test_get_form_invalid_ct_field_raises(self):
class GenericPolymorphicInlineFormSetTest (line 380) | class GenericPolymorphicInlineFormSetTest(TestCase):
method setUp (line 383) | def setUp(self):
method test_factory_creates_functional_formset (line 387) | def test_factory_creates_functional_formset(self):
method test_formset_gfk_fields_excluded (line 402) | def test_formset_gfk_fields_excluded(self):
method test_extra_forms_cycle_child_types (line 418) | def test_extra_forms_cycle_child_types(self):
method test_bound_formset_with_existing_objects (line 436) | def test_bound_formset_with_existing_objects(self):
method test_formset_with_child_form_kwargs (line 484) | def test_formset_with_child_form_kwargs(self):
method test_empty_forms_property (line 497) | def test_empty_forms_property(self):
method test_empty_form_raises_runtime_error (line 516) | def test_empty_form_raises_runtime_error(self):
method test_unsupported_child_type_in_bound_data (line 530) | def test_unsupported_child_type_in_bound_data(self):
method test_validation_error_missing_ctype (line 554) | def test_validation_error_missing_ctype(self):
method test_is_multipart_with_file_field (line 576) | def test_is_multipart_with_file_field(self):
method test_media_aggregation (line 597) | def test_media_aggregation(self):
method test_save_new_objects (line 619) | def test_save_new_objects(self):
FILE: src/polymorphic/tests/test_inheritance.py
class InheritanceTests (line 6) | class InheritanceTests(TestCase):
method test_mixin_inherited_managers (line 7) | def test_mixin_inherited_managers(self):
FILE: src/polymorphic/tests/test_migration_managers.py
class TestRelatedManagersInMigrationState (line 9) | class TestRelatedManagersInMigrationState(MigratorTestCase):
method test_migration_managers_are_nonpoly (line 18) | def test_migration_managers_are_nonpoly(self):
FILE: src/polymorphic/tests/test_migrations/models.py
function get_default_related (line 5) | def get_default_related():
class RelatedModel (line 10) | class RelatedModel(models.Model):
class BasePolyModel (line 16) | class BasePolyModel(PolymorphicModel):
class ChildPolyModel (line 25) | class ChildPolyModel(BasePolyModel):
class GrandChildPolyModel (line 31) | class GrandChildPolyModel(ChildPolyModel):
class ModelWithCascade (line 41) | class ModelWithCascade(PolymorphicModel):
class ModelWithProtect (line 47) | class ModelWithProtect(PolymorphicModel):
class ModelWithSetNull (line 53) | class ModelWithSetNull(PolymorphicModel):
class ModelWithSetDefault (line 59) | class ModelWithSetDefault(PolymorphicModel):
class ModelWithSet (line 67) | class ModelWithSet(PolymorphicModel):
class ModelWithDoNothing (line 73) | class ModelWithDoNothing(PolymorphicModel):
class ModelWithRestrict (line 79) | class ModelWithRestrict(PolymorphicModel):
class ModelWithOneToOneCascade (line 88) | class ModelWithOneToOneCascade(PolymorphicModel):
class ModelWithOneToOneProtect (line 94) | class ModelWithOneToOneProtect(PolymorphicModel):
class ModelWithOneToOneSetNull (line 102) | class ModelWithOneToOneSetNull(PolymorphicModel):
FILE: src/polymorphic/tests/test_migrations/test_on_delete.py
class OnDeleteSerializationTest (line 21) | class OnDeleteSerializationTest(GeneratedMigrationsPerClassMixin, Transa...
method state (line 29) | def state(self):
method setUpClass (line 33) | def setUpClass(cls):
method test_migration_managers_non_polymorphic (line 38) | def test_migration_managers_non_polymorphic(self):
method test_foreign_keys_wrapped_with_PolymorphicGuard (line 92) | def test_foreign_keys_wrapped_with_PolymorphicGuard(self):
method test_one_to_one_wrapped_with_PolymorphicGuard (line 127) | def test_one_to_one_wrapped_with_PolymorphicGuard(self):
method test_cascade_serialization (line 153) | def test_cascade_serialization(self):
method test_protect_serialization (line 167) | def test_protect_serialization(self):
method test_set_null_serialization (line 179) | def test_set_null_serialization(self):
method test_set_default_serialization (line 191) | def test_set_default_serialization(self):
method test_set_callable_serialization (line 203) | def test_set_callable_serialization(self):
method test_do_nothing_serialization (line 217) | def test_do_nothing_serialization(self):
method test_restrict_serialization (line 229) | def test_restrict_serialization(self):
method test_migration_file_generated (line 241) | def test_migration_file_generated(self):
method test_migration_file_content (line 247) | def test_migration_file_content(self):
method test_migration_serialization_stability (line 273) | def test_migration_serialization_stability(self):
method test_PolymorphicGuard_unwraps_correctly (line 287) | def test_PolymorphicGuard_unwraps_correctly(self):
method test_all_on_delete_types_covered (line 300) | def test_all_on_delete_types_covered(self):
method test_guard_equality_with_same_guard (line 347) | def test_guard_equality_with_same_guard(self):
method test_guard_equality_with_different_guard (line 355) | def test_guard_equality_with_different_guard(self):
method test_guard_equality_with_non_serializable_object (line 363) | def test_guard_equality_with_non_serializable_object(self):
method test_guard_equality_with_serialization_exception (line 378) | def test_guard_equality_with_serialization_exception(self):
class PolymorphicInheritanceSerializationTest (line 394) | class PolymorphicInheritanceSerializationTest(TestCase):
method test_polymorphic_inheritance_chain (line 399) | def test_polymorphic_inheritance_chain(self):
class OnDeleteBehaviorTest (line 417) | class OnDeleteBehaviorTest(GeneratedMigrationsPerClassMixin, Transaction...
method test_cascade_deletes_related_objects (line 427) | def test_cascade_deletes_related_objects(self):
method test_protect_prevents_deletion (line 445) | def test_protect_prevents_deletion(self):
method test_set_null_sets_field_to_null (line 461) | def test_set_null_sets_field_to_null(self):
method test_set_default_sets_field_to_default (line 480) | def test_set_default_sets_field_to_default(self):
method test_set_callable_uses_function (line 499) | def test_set_callable_uses_function(self):
method test_do_nothing_behavior (line 518) | def test_do_nothing_behavior(self):
method test_restrict_prevents_deletion_when_objects_exist (line 540) | def test_restrict_prevents_deletion_when_objects_exist(self):
method test_cascade_with_polymorphic_inheritance (line 556) | def test_cascade_with_polymorphic_inheritance(self):
method test_one_to_one_cascade_deletes_related_object (line 579) | def test_one_to_one_cascade_deletes_related_object(self):
method test_one_to_one_protect_prevents_deletion (line 597) | def test_one_to_one_protect_prevents_deletion(self):
method test_one_to_one_set_null_sets_to_null (line 613) | def test_one_to_one_set_null_sets_to_null(self):
FILE: src/polymorphic/tests/test_multidb.py
class MultipleDatabasesTests (line 23) | class MultipleDatabasesTests(TestCase):
method test_save_to_non_default_database (line 26) | def test_save_to_non_default_database(self):
method test_instance_of_filter_on_non_default_database (line 44) | def test_instance_of_filter_on_non_default_database(self):
method test_forward_many_to_one_descriptor_on_non_default_database (line 78) | def test_forward_many_to_one_descriptor_on_non_default_database(self):
method test_reverse_many_to_one_descriptor_on_non_default_database (line 89) | def test_reverse_many_to_one_descriptor_on_non_default_database(self):
method test_reverse_one_to_one_descriptor_on_non_default_database (line 100) | def test_reverse_one_to_one_descriptor_on_non_default_database(self):
method test_many_to_many_descriptor_on_non_default_database (line 113) | def test_many_to_many_descriptor_on_non_default_database(self):
method test_deletion_cascade_on_non_default_db (line 125) | def test_deletion_cascade_on_non_default_db(self):
method test_create_from_super (line 141) | def test_create_from_super(self):
method test_cross_database_save (line 280) | def test_cross_database_save(self):
method test_database_router_respected (line 311) | def test_database_router_respected(self):
method test_save_respects_db_for_write_router (line 336) | def test_save_respects_db_for_write_router(self):
FILE: src/polymorphic/tests/test_orm.py
class PolymorphicTests (line 126) | class PolymorphicTests(TransactionTestCase):
method test_annotate_aggregate_order (line 131) | def test_annotate_aggregate_order(self):
method test_limit_choices_to (line 184) | def test_limit_choices_to(self):
method test_primary_key_custom_field_problem (line 195) | def test_primary_key_custom_field_problem(self):
method create_model2abcd (line 236) | def create_model2abcd(self):
method test_simple_inheritance (line 248) | def test_simple_inheritance(self):
method test_defer_fields (line 259) | def test_defer_fields(self):
method test_defer_related_fields (line 315) | def test_defer_related_fields(self):
method test_manual_get_real_instance (line 344) | def test_manual_get_real_instance(self):
method test_get_real_instance_with_stale_content_type (line 350) | def test_get_real_instance_with_stale_content_type(self):
method test_get_real_concrete_instance_class_id_with_stale_content_type (line 359) | def test_get_real_concrete_instance_class_id_with_stale_content_type(s...
method test_get_real_concrete_instance_class_with_stale_content_type (line 368) | def test_get_real_concrete_instance_class_with_stale_content_type(self):
method test_get_real_concrete_instance_class_with_proxy_model (line 377) | def test_get_real_concrete_instance_class_with_proxy_model(self):
method test_non_polymorphic (line 386) | def test_non_polymorphic(self):
method test_get_real_instances (line 396) | def test_get_real_instances(self):
method test_queryset_missing_derived (line 420) | def test_queryset_missing_derived(self):
method test_queryset_missing_contenttype (line 443) | def test_queryset_missing_contenttype(self):
method test_translate_polymorphic_q_object (line 458) | def test_translate_polymorphic_q_object(self):
method test_create_instanceof_q (line 467) | def test_create_instanceof_q(self):
method test_instance_of_single_lazy_query (line 493) | def test_instance_of_single_lazy_query(self):
method test_base_manager (line 515) | def test_base_manager(self):
method test_default_manager (line 547) | def test_default_manager(self):
method test_foreignkey_field (line 581) | def test_foreignkey_field(self):
method test_parentage_links_are_non_polymorphic (line 590) | def test_parentage_links_are_non_polymorphic(self):
method test_onetoone_field (line 617) | def test_onetoone_field(self):
method test_manytomany_field (line 632) | def test_manytomany_field(self):
method test_extra_method (line 679) | def test_extra_method(self):
method test_instance_of_filter (line 728) | def test_instance_of_filter(self):
method test_polymorphic___filter (line 760) | def test_polymorphic___filter(self):
method test_polymorphic_applabel___filter (line 768) | def test_polymorphic_applabel___filter(self):
method test_query_filter_exclude_is_immutable (line 779) | def test_query_filter_exclude_is_immutable(self):
method test_polymorphic___filter_field (line 796) | def test_polymorphic___filter_field(self):
method test_polymorphic___filter_reverse_field (line 804) | def test_polymorphic___filter_reverse_field(self):
method test_delete (line 812) | def test_delete(self):
method test_combine_querysets (line 828) | def test_combine_querysets(self):
method test_multiple_inheritance (line 838) | def test_multiple_inheritance(self):
method test_relation_base (line 854) | def test_relation_base(self):
method test_user_defined_manager (line 917) | def test_user_defined_manager(self):
method test_user_defined_manager_as_secondary (line 933) | def test_user_defined_manager_as_secondary(self):
method test_user_objects_manager_as_secondary (line 953) | def test_user_objects_manager_as_secondary(self):
method test_user_defined_queryset_as_manager (line 962) | def test_user_defined_queryset_as_manager(self):
method test_manager_inheritance (line 983) | def test_manager_inheritance(self):
method test_queryset_assignment (line 987) | def test_queryset_assignment(self):
method test_proxy_models (line 1010) | def test_proxy_models(self):
method test_queryset_on_proxy_model_does_not_return_superclasses (line 1024) | def test_queryset_on_proxy_model_does_not_return_superclasses(self):
method test_proxy_get_real_instance_class (line 1034) | def test_proxy_get_real_instance_class(self):
method test_content_types_for_proxy_models (line 1053) | def test_content_types_for_proxy_models(self):
method test_proxy_model_inheritance (line 1060) | def test_proxy_model_inheritance(self):
method test_custom_pk (line 1100) | def test_custom_pk(self):
method test_fix_getattribute (line 1111) | def test_fix_getattribute(self):
method test_parent_link_and_related_name (line 1121) | def test_parent_link_and_related_name(self):
method test_polymorphic__accessor_caching (line 1140) | def test_polymorphic__accessor_caching(self):
method test_polymorphic__aggregate (line 1163) | def test_polymorphic__aggregate(self):
method test_polymorphic__aggregate_empty_queryset (line 1181) | def test_polymorphic__aggregate_empty_queryset(self):
method test_polymorphic__complex_aggregate (line 1187) | def test_polymorphic__complex_aggregate(self):
method test_annotate_f_expression (line 1226) | def test_annotate_f_expression(self):
method test_polymorphic__filtered_relation (line 1255) | def test_polymorphic__filtered_relation(self):
method test_polymorphic__expressions (line 1300) | def test_polymorphic__expressions(self):
method test_null_polymorphic_id (line 1307) | def test_null_polymorphic_id(self):
method test_invalid_polymorphic_id (line 1317) | def test_invalid_polymorphic_id(self):
method test_bulk_create_abstract_inheritance (line 1328) | def test_bulk_create_abstract_inheritance(self):
method test_bulk_create_proxy_inheritance (line 1340) | def test_bulk_create_proxy_inheritance(self):
method test_bulk_create_unsupported_multi_table_inheritance (line 1372) | def test_bulk_create_unsupported_multi_table_inheritance(self):
method test_bulk_create_ignore_conflicts (line 1378) | def test_bulk_create_ignore_conflicts(self):
method test_bulk_create_no_ignore_conflicts (line 1395) | def test_bulk_create_no_ignore_conflicts(self):
method test_can_query_using_subclass_selector_on_abstract_model (line 1406) | def test_can_query_using_subclass_selector_on_abstract_model(self):
method test_intermediate_abstract_descriptors (line 1415) | def test_intermediate_abstract_descriptors(self):
method test_can_query_using_subclass_selector_on_proxy_model (line 1422) | def test_can_query_using_subclass_selector_on_proxy_model(self):
method test_intermediate_proxy_descriptors (line 1431) | def test_intermediate_proxy_descriptors(self):
method test_prefetch_related_behaves_normally_with_polymorphic_model (line 1441) | def test_prefetch_related_behaves_normally_with_polymorphic_model(self):
method test_prefetch_related_with_missing (line 1450) | def test_prefetch_related_with_missing(self):
method test_refresh_from_db_fields (line 1479) | def test_refresh_from_db_fields(self):
method test_non_polymorphic_parent (line 1490) | def test_non_polymorphic_parent(self):
method test_iteration (line 1494) | def test_iteration(self):
method test_transmogrify_with_init (line 1661) | def test_transmogrify_with_init(self):
method test_subqueries (line 1671) | def test_subqueries(self):
method test_one_to_one_primary_key (line 1739) | def test_one_to_one_primary_key(self):
method test_manager_override (line 1837) | def test_manager_override(self):
method test_abstract_managers (line 1856) | def test_abstract_managers(self):
method test_fk_polymorphism (line 1900) | def test_fk_polymorphism(self):
method test_polymorphic_extension (line 1914) | def test_polymorphic_extension(self):
method test_manytomany_without_through_field (line 1942) | def test_manytomany_without_through_field(self):
method test_manytomany_with_through_field (line 1954) | def test_manytomany_with_through_field(self):
method test_create_from_super (line 1966) | def test_create_from_super(self):
method test_create_from_super_child_exists (line 2106) | def test_create_from_super_child_exists(self):
method test_through_models_creates_and_reads (line 2132) | def test_through_models_creates_and_reads(self):
method test_through_model_updates (line 2170) | def test_through_model_updates(self):
method test_infinite_recursion_with_only (line 2193) | def test_infinite_recursion_with_only(self):
method test_generic_relation_prefetch (line 2213) | def test_generic_relation_prefetch(self):
method test_besteffort_iteration (line 2248) | def test_besteffort_iteration(self):
method test_besteffort_get_real_instance (line 2269) | def test_besteffort_get_real_instance(self):
method test_queryset_first_returns_none_on_empty_queryset (line 2280) | def test_queryset_first_returns_none_on_empty_queryset(self):
method test_queryset_getitem_raises_indexerror_on_empty_queryset (line 2283) | def test_queryset_getitem_raises_indexerror_on_empty_queryset(self):
method test_queryset_getitem_negative_index_raises_valueerror (line 2287) | def test_queryset_getitem_negative_index_raises_valueerror(self):
method test_queryset_getitem_slice_returns_objects (line 2292) | def test_queryset_getitem_slice_returns_objects(self):
method test_aggregate_with_filtered_relation (line 2299) | def test_aggregate_with_filtered_relation(self):
method test_aggregate_with_nested_q_objects (line 2323) | def test_aggregate_with_nested_q_objects(self):
method test_aggregate_with_subclass_field_in_expression (line 2343) | def test_aggregate_with_subclass_field_in_expression(self):
method test_get_best_effort_instance_with_missing_derived (line 2362) | def test_get_best_effort_instance_with_missing_derived(self):
method test_get_best_effort_instance_with_annotations (line 2379) | def test_get_best_effort_instance_with_annotations(self):
method test_get_best_effort_instance_with_extra_select (line 2397) | def test_get_best_effort_instance_with_extra_select(self):
method test_get_best_effort_instance_multiple_inheritance_levels (line 2415) | def test_get_best_effort_instance_multiple_inheritance_levels(self):
method test_deferred_loading_with_subclass_syntax (line 2440) | def test_deferred_loading_with_subclass_syntax(self):
method test_deferred_loading_with_nonexistent_field (line 2455) | def test_deferred_loading_with_nonexistent_field(self):
method test_only_with_subclass_syntax (line 2468) | def test_only_with_subclass_syntax(self):
method test_real_instances_with_stale_content_type (line 2483) | def test_real_instances_with_stale_content_type(self):
method test_real_instances_with_proxy_model (line 2491) | def test_real_instances_with_proxy_model(self):
method test_annotate_with_polymorphic_field_path (line 2502) | def test_annotate_with_polymorphic_field_path(self):
method test_aggregate_with_polymorphic_field_path (line 2514) | def test_aggregate_with_polymorphic_field_path(self):
method test_disparate_pk_values_in_hierarchy (line 2527) | def test_disparate_pk_values_in_hierarchy(self):
method test_manager_cache_clear_persistence (line 2623) | def test_manager_cache_clear_persistence(self):
FILE: src/polymorphic/tests/test_performance.py
class PerformanceTests (line 10) | class PerformanceTests(TransactionTestCase):
method test_baseline_number_of_queries (line 11) | def test_baseline_number_of_queries(self):
FILE: src/polymorphic/tests/test_query_translate.py
class QueryTranslateTests (line 13) | class QueryTranslateTests(TestCase):
method test_translate_with_not_pickleable_query (line 14) | def test_translate_with_not_pickleable_query(self):
method test_deep_copy_of_q_objects (line 54) | def test_deep_copy_of_q_objects(self):
method test_proxy_model_query_related_name (line 81) | def test_proxy_model_query_related_name(self):
FILE: src/polymorphic/tests/test_regression.py
class RegressionTests (line 26) | class RegressionTests(TestCase):
method test_for_query_result_incomplete_with_inheritance (line 27) | def test_for_query_result_incomplete_with_inheritance(self):
method test_pr_254 (line 58) | def test_pr_254(self):
method test_alias_queryset (line 96) | def test_alias_queryset(self):
method test_alias_advanced (line 129) | def test_alias_advanced(self):
method test_upcasting_to_sibling_class (line 166) | def test_upcasting_to_sibling_class(self):
method test_mixed_inheritance_save_issue_495 (line 189) | def test_mixed_inheritance_save_issue_495(self):
method test_create_or_update (line 237) | def test_create_or_update(self):
method test_double_underscore_in_related_name (line 269) | def test_double_underscore_in_related_name(self):
method test_issue_252_abstract_base_class (line 284) | def test_issue_252_abstract_base_class(self):
class SpecialBookForm (line 330) | class SpecialBookForm(forms.ModelForm):
class Meta (line 331) | class Meta:
class TestFormsetExclude (line 336) | class TestFormsetExclude(TestCase):
method test_formset_child_respects_exclude (line 337) | def test_formset_child_respects_exclude(self):
method test_formset_initial_with_contenttype_instance (line 346) | def test_formset_initial_with_contenttype_instance(self):
method test_formset_with_none_instance (line 375) | def test_formset_with_none_instance(self):
method test_combined_formset_behaviors (line 412) | def test_combined_formset_behaviors(self):
FILE: src/polymorphic/tests/test_serialization.py
function call_dumpdata (line 40) | def call_dumpdata(*models, natural_foreign=True, natural_primary=True, a...
function run_dumpdata (line 54) | def run_dumpdata(*models, natural_foreign=True, natural_primary=True, al...
function dump_objects (line 68) | def dump_objects(db):
function natkey_dump_objects (line 80) | def natkey_dump_objects(db):
function test_dumpdata_returns_base_objects_not_downcasted (line 109) | def test_dumpdata_returns_base_objects_not_downcasted(dumpdata, dump_obj...
function test_dumpdata_all_flag (line 167) | def test_dumpdata_all_flag(dumpdata, dump_objects, all):
function test_dumpdata_child_model_only (line 233) | def test_dumpdata_child_model_only(dumpdata, dump_objects):
function test_dumpdata_multi_table_roundtrip (line 263) | def test_dumpdata_multi_table_roundtrip(dumpdata, dump_objects, all):
function test_dumpdata_related_polymorphic_roundtrip (line 462) | def test_dumpdata_related_polymorphic_roundtrip(dumpdata, dump_objects, ...
function test_dumpdata_natural_keys (line 583) | def test_dumpdata_natural_keys(dumpdata, natkey_dump_objects):
FILE: src/polymorphic/tests/test_signals.py
class TestSignals (line 9) | class TestSignals(TestCase):
method test_first_behavior_during_post_delete_signal_1 (line 10) | def test_first_behavior_during_post_delete_signal_1(self):
method test_first_behavior_during_post_delete_signal_2 (line 34) | def test_first_behavior_during_post_delete_signal_2(self):
method test_getitem_behavior_during_post_delete_signal (line 50) | def test_getitem_behavior_during_post_delete_signal(self):
method test_normal_getitem_behavior_during_post_delete_signal (line 70) | def test_normal_getitem_behavior_during_post_delete_signal(self):
method test_queryset_first_returns_remaining_object_in_post_delete_signal (line 89) | def test_queryset_first_returns_remaining_object_in_post_delete_signal...
method test_queryset_getitem_returns_remaining_object_in_post_delete_signal (line 126) | def test_queryset_getitem_returns_remaining_object_in_post_delete_sign...
method test_queryset_first_works_when_deleted_object_created_second (line 165) | def test_queryset_first_works_when_deleted_object_created_second(self):
method test_besteffort_iteration_avoids_nplusone (line 198) | def test_besteffort_iteration_avoids_nplusone(self):
FILE: src/polymorphic/tests/test_templatetags.py
function parse_json_from_template (line 19) | def parse_json_from_template(result):
class BreadcrumbScopeTagTest (line 24) | class BreadcrumbScopeTagTest(TestCase):
method test_breadcrumb_scope_sets_app_label (line 27) | def test_breadcrumb_scope_sets_app_label(self):
method test_breadcrumb_scope_sets_opts (line 38) | def test_breadcrumb_scope_sets_opts(self):
method test_breadcrumb_scope_restores_context (line 49) | def test_breadcrumb_scope_restores_context(self):
method test_breadcrumb_scope_with_none_base_opts (line 62) | def test_breadcrumb_scope_with_none_base_opts(self):
method test_breadcrumb_scope_with_string_base_opts (line 74) | def test_breadcrumb_scope_with_string_base_opts(self):
method test_breadcrumb_scope_missing_argument_raises_error (line 86) | def test_breadcrumb_scope_missing_argument_raises_error(self):
method test_breadcrumb_scope_too_many_arguments_raises_error (line 93) | def test_breadcrumb_scope_too_many_arguments_raises_error(self):
method test_breadcrumb_scope_with_variable_lookup (line 101) | def test_breadcrumb_scope_with_variable_lookup(self):
class IncludeEmptyFormFilterTest (line 113) | class IncludeEmptyFormFilterTest(TestCase):
method test_include_empty_form_with_polymorphic_formset (line 116) | def test_include_empty_form_with_polymorphic_formset(self):
method test_include_empty_form_with_standard_formset (line 141) | def test_include_empty_form_with_standard_formset(self):
method test_include_empty_form_with_empty_polymorphic_formset (line 159) | def test_include_empty_form_with_empty_polymorphic_formset(self):
class AsScriptOptionsFilterTest (line 184) | class AsScriptOptionsFilterTest(TestCase):
method test_as_script_options_returns_valid_json (line 187) | def test_as_script_options_returns_valid_json(self):
method test_as_script_options_contains_prefix (line 207) | def test_as_script_options_contains_prefix(self):
method test_as_script_options_contains_pk_field_name (line 227) | def test_as_script_options_contains_pk_field_name(self):
method test_as_script_options_contains_add_text (line 247) | def test_as_script_options_contains_add_text(self):
method test_as_script_options_contains_show_add_button (line 267) | def test_as_script_options_contains_show_add_button(self):
method test_as_script_options_contains_delete_text (line 287) | def test_as_script_options_contains_delete_text(self):
method test_as_script_options_polymorphic_contains_child_types (line 307) | def test_as_script_options_polymorphic_contains_child_types(self):
method test_as_script_options_child_types_have_name_and_type (line 332) | def test_as_script_options_child_types_have_name_and_type(self):
method test_as_script_options_standard_formset_no_child_types (line 353) | def test_as_script_options_standard_formset_no_child_types(self):
method test_as_script_options_custom_verbose_name (line 367) | def test_as_script_options_custom_verbose_name(self):
method test_as_script_options_custom_add_text (line 387) | def test_as_script_options_custom_add_text(self):
method test_as_script_options_custom_show_add_button (line 407) | def test_as_script_options_custom_show_add_button(self):
class AsFormTypeFilterTest (line 428) | class AsFormTypeFilterTest(TestCase):
method test_as_form_type_returns_model_name (line 431) | def test_as_form_type_returns_model_name(self):
method test_as_form_type_with_model2a_form (line 452) | def test_as_form_type_with_model2a_form(self):
method test_as_form_type_with_model2b_form (line 471) | def test_as_form_type_with_model2b_form(self):
class AsModelNameFilterTest (line 491) | class AsModelNameFilterTest(TestCase):
method test_as_model_name_with_model_class (line 494) | def test_as_model_name_with_model_class(self):
method test_as_model_name_with_model_instance (line 502) | def test_as_model_name_with_model_instance(self):
method test_as_model_name_with_child_model (line 512) | def test_as_model_name_with_child_model(self):
method test_as_model_name_with_child_model_instance (line 520) | def test_as_model_name_with_child_model_instance(self):
method test_as_model_name_in_loop (line 530) | def test_as_model_name_in_loop(self):
FILE: src/polymorphic/tests/test_utils.py
class UtilsTests (line 23) | class UtilsTests(TransactionTestCase):
method test_sort_by_subclass (line 24) | def test_sort_by_subclass(self):
method test_reset_polymorphic_ctype (line 33) | def test_reset_polymorphic_ctype(self):
method test_get_base_polymorphic_model (line 54) | def test_get_base_polymorphic_model(self):
method test_get_base_polymorphic_model_skip_abstract (line 70) | def test_get_base_polymorphic_model_skip_abstract(self):
method test_concrete_descendants (line 91) | def test_concrete_descendants(self):
method test_route_to_ancestor (line 206) | def test_route_to_ancestor(self):
class PrepareForCopyTests (line 330) | class PrepareForCopyTests(TransactionTestCase):
method test_copy_polymorphic_objects (line 331) | def test_copy_polymorphic_objects(self):
method test_prepare_for_copy_edge_cases (line 446) | def test_prepare_for_copy_edge_cases(self):
method test_prepare_for_copy_upcast (line 550) | def test_prepare_for_copy_upcast(self):
method test_prepare_for_copy_plain (line 571) | def test_prepare_for_copy_plain(self):
method test_copy_with_abstract_base (line 587) | def test_copy_with_abstract_base(self):
method test_copy_with_proxies (line 612) | def test_copy_with_proxies(self):
method test_model_registration_and_utils_caches (line 638) | def test_model_registration_and_utils_caches(self):
FILE: src/polymorphic/tests/utils.py
function is_sqlite_in_memory (line 24) | def is_sqlite_in_memory(db_name: str = "default") -> bool:
function is_oracle (line 34) | def is_oracle(db_name: str = "default") -> bool:
function get_subprocess_test_db_env (line 40) | def get_subprocess_test_db_env(db_name: str = "default") -> dict[str, str]:
class GeneratedMigrationsPerClassMixin (line 78) | class GeneratedMigrationsPerClassMixin:
method setUpClass (line 92) | def setUpClass(cls):
method tearDownClass (line 118) | def tearDownClass(cls):
method _find_latest_migration_name (line 141) | def _find_latest_migration_name(cls, app_label: str) -> str:
class _GenericUITest (line 156) | class _GenericUITest(StaticLiveServerTestCase):
method admin_url (line 167) | def admin_url(self):
method add_url (line 170) | def add_url(self, model):
method change_url (line 174) | def change_url(self, model, id):
method list_url (line 181) | def list_url(self, model):
method get_object_ids (line 185) | def get_object_ids(self, model):
method setUpClass (line 192) | def setUpClass(cls):
method tearDownClass (line 208) | def tearDownClass(cls):
method setUp (line 215) | def setUp(self):
method tearDown (line 230) | def tearDown(self):
FILE: src/polymorphic/utils.py
class ParentLinkInfo (line 16) | class ParentLinkInfo:
function reset_polymorphic_ctype (line 25) | def reset_polymorphic_ctype(*models: type[models.Model], **filters: Any)...
function _compare_mro (line 56) | def _compare_mro(cls1: type, cls2: type) -> int:
function sort_by_subclass (line 73) | def sort_by_subclass(*classes: type[models.Model]) -> list[type[models.M...
function get_base_polymorphic_model (line 83) | def get_base_polymorphic_model(
function route_to_ancestor (line 103) | def route_to_ancestor(
function is_model_loaded (line 143) | def is_model_loaded(model: type[models.Model]) -> bool:
function concrete_descendants (line 152) | def concrete_descendants(
function prepare_for_copy (line 181) | def prepare_for_copy(obj: models.Model) -> None:
function _lazy_ctype (line 248) | def _lazy_ctype(model: type[models.Model], using: str = DEFAULT_DB_ALIAS...
function lazy_ctype (line 258) | def lazy_ctype(model: type[models.Model], using: str = DEFAULT_DB_ALIAS)...
function _map_queryname_to_class (line 277) | def _map_queryname_to_class(base_model: type[models.Model], qry_name: st...
function _clear_utility_caches (line 300) | def _clear_utility_caches() -> None:
Condensed preview — 240 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,305K chars).
[
{
"path": ".github/CODEOWNERS",
"chars": 33,
"preview": "# Default: everything\n* @bckohan\n"
},
{
"path": ".github/dependabot.yml",
"chars": 527,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/bandit.yml",
"chars": 1467,
"preview": "name: Bandit\n\non:\n push:\n branches: [ main ]\n pull_request:\n paths:\n - \"src/**\"\n - \"pyproject.toml\"\n "
},
{
"path": ".github/workflows/lint.yml",
"chars": 2384,
"preview": "name: Lint\n\npermissions:\n contents: read\n\non:\n push:\n tags-ignore:\n - '*'\n branches:\n - '*'\n pull_req"
},
{
"path": ".github/workflows/release.yml",
"chars": 5753,
"preview": "name: Publish Release\n\npermissions: read-all\n\nconcurrency:\n # stop previous release runs if tag is recreated\n group: r"
},
{
"path": ".github/workflows/scorecard.yml",
"chars": 2658,
"preview": "name: OpenSSF Scorecard\non:\n # For Branch-Protection check. Only the default branch is supported. See\n # https://githu"
},
{
"path": ".github/workflows/test.yml",
"chars": 27535,
"preview": "name: Test\n\npermissions:\n contents: read\n\non:\n push:\n tags-ignore:\n - '*'\n branches: ['main']\n pull_reques"
},
{
"path": ".github/workflows/update_coc.yml",
"chars": 1802,
"preview": "name: Update Code of Conduct\n\npermissions: read-all\n\non:\n workflow_dispatch:\n # Run every Sunday at midnight UTC (00:0"
},
{
"path": ".github/workflows/zizmor.yml",
"chars": 1625,
"preview": "name: Zizmor\n\non:\n push:\n branches: [ main ]\n pull_request:\n paths:\n - \".github/workflows/**/*.yml\"\n sched"
},
{
"path": ".gitignore",
"chars": 4748,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[codz]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packag"
},
{
"path": ".pre-commit-config.yaml",
"chars": 607,
"preview": "ci:\n # Don't run these in pre-commit.ci at all\n skip: [lint, format, docs, pip]\n\nrepos:\n - repo: local\n hooks:\n "
},
{
"path": ".readthedocs.yaml",
"chars": 648,
"preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
},
{
"path": "AUTHORS.md",
"chars": 1536,
"preview": "# Current Maintainer(s)\n\n* Brian Kohan\n\n## Contributors\n\n* Abel Daniel\n* Adam Chainz\n* Adam Wentz\n* Adam Donaghy\n* Andre"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5223,
"preview": "\n# Django Commons Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation "
},
{
"path": "CONTRIBUTING.md",
"chars": 7758,
"preview": "# Contributing\n\nContributions are encouraged! Please use the issue page to submit feature requests or bug reports. Issue"
},
{
"path": "LICENSE",
"chars": 1571,
"preview": "Copyright (c) 2009 or later by the individual contributors.\nPlease see the AUTHORS file.\n\nAll rights reserved.\n\r\nRedistr"
},
{
"path": "README.md",
"chars": 5396,
"preview": "# django-polymorphic\n\n[](https://opensource.org/licens"
},
{
"path": "SECURITY.md",
"chars": 1259,
"preview": "# Security Policy\n\n[:\n # stash it somewhere glob"
},
{
"path": "docs/_ext/djangodummy/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "docs/_ext/djangodummy/requirements.txt",
"chars": 163,
"preview": "# for readthedocs\n# Remaining requirements are picked up from setup.py\nDjango>=4.2.20\ndjango-extra-views>=0.14.0\nsphinxc"
},
{
"path": "docs/_ext/djangodummy/settings.py",
"chars": 391,
"preview": "# Settings file to allow parsing API documentation of Django modules,\n# and provide defaults to use in the documentation"
},
{
"path": "docs/_static/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "docs/_static/style.css",
"chars": 1158,
"preview": "section#api-documentation div.highlight pre {\n color: #b30000;\n display: block; /* ensures it's treated "
},
{
"path": "docs/admin.rst",
"chars": 10683,
"preview": "Admin Integration\n=================\n\nOf course, it's possible to register individual polymorphic models in the\n:doc:`Dja"
},
{
"path": "docs/advanced.rst",
"chars": 18781,
"preview": ".. _advanced-features:\n\nAdvanced Features\n=================\n\nIn the examples below, these models are being used:\n\n.. cod"
},
{
"path": "docs/api/index.rst",
"chars": 374,
"preview": "API Documentation\n=================\n\n.. _base:\n\n.. automodule:: polymorphic\n :members:\n :show-inheritance:\n :inher"
},
{
"path": "docs/api/polymorphic.admin.rst",
"chars": 1951,
"preview": "polymorphic.admin\n=================\n\nModelAdmin classes\n------------------\n\nThe ``PolymorphicParentModelAdmin`` class\n~~"
},
{
"path": "docs/api/polymorphic.contrib/drf.rst",
"chars": 142,
"preview": "drf.serializers\n===============\n\n.. automodule:: polymorphic.contrib.drf.serializers\n :members:\n :undoc-members:\n "
},
{
"path": "docs/api/polymorphic.contrib/extra_views.rst",
"chars": 130,
"preview": "extra_views\n===========\n\n.. automodule:: polymorphic.contrib.extra_views\n :members:\n :undoc-members:\n :show-inh"
},
{
"path": "docs/api/polymorphic.contrib/guardian.rst",
"chars": 121,
"preview": "guardian\n========\n\n.. automodule:: polymorphic.contrib.guardian\n :members:\n :undoc-members:\n :show-inheritance:"
},
{
"path": "docs/api/polymorphic.contrib/index.rst",
"chars": 198,
"preview": "polymorphic.contrib\n===================\n\n.. _contrib:\n\n.. automodule:: polymorphic.contrib\n :members:\n :show-inherit"
},
{
"path": "docs/api/polymorphic.deletion.rst",
"chars": 281,
"preview": "polymorphic.deletion\n====================\n\n.. automodule:: polymorphic.deletion\n\n.. autoclass:: polymorphic.deletion.Pol"
},
{
"path": "docs/api/polymorphic.formsets.rst",
"chars": 939,
"preview": "polymorphic.formsets\n====================\n\n.. automodule:: polymorphic.formsets\n\n\nModel formsets\n--------------\n\n.. auto"
},
{
"path": "docs/api/polymorphic.managers.rst",
"chars": 1248,
"preview": "polymorphic.managers\n====================\n\n.. automodule:: polymorphic.managers\n\n\nThe ``PolymorphicManager`` class\n-----"
},
{
"path": "docs/api/polymorphic.models.rst",
"chars": 133,
"preview": "polymorphic.models\n==================\n\n.. automodule:: polymorphic.models\n :members:\n :show-inheritance:\n :priv"
},
{
"path": "docs/api/polymorphic.showfields.rst",
"chars": 144,
"preview": "polymorphic.showfields\n======================\n\n.. automodule:: polymorphic.showfields\n :members:\n :show-inheritance:"
},
{
"path": "docs/api/polymorphic.templatetags/index.rst",
"chars": 180,
"preview": "polymorphic.templatetags\n========================\n\n.. _templatetags:\n\n.. automodule:: polymorphic.templatetags\n\n.. toctr"
},
{
"path": "docs/api/polymorphic.templatetags/polymorphic_admin_tags.rst",
"chars": 125,
"preview": "polymorphic_admin_tags\n======================\n\n.. automodule:: polymorphic.templatetags.polymorphic_admin_tags\n :memb"
},
{
"path": "docs/api/polymorphic.templatetags/polymorphic_formset_tags.rst",
"chars": 131,
"preview": "polymorphic_formset_tags\n========================\n\n.. automodule:: polymorphic.templatetags.polymorphic_formset_tags\n "
},
{
"path": "docs/api/polymorphic.utils.rst",
"chars": 85,
"preview": "polymorphic.utils\n=================\n\n.. automodule:: polymorphic.utils\n :members:\n"
},
{
"path": "docs/changelog/drf.rst",
"chars": 963,
"preview": ".. :drf_changelog:\n\ndrf\n---\n\nBelow is the changelog for the :pypi:`django-rest-polymorphic` before it was included into\n"
},
{
"path": "docs/changelog/index.rst",
"chars": 42694,
"preview": "Changelog\n=========\n\nv4.11.3 (2026-04-30)\n--------------------\n\n* `django-polymorphic <https://github.com/django-commons"
},
{
"path": "docs/conf.py",
"chars": 10352,
"preview": "#\n# django-polymorphic documentation build configuration file, created by\n# sphinx-quickstart on Sun May 19 12:20:47 201"
},
{
"path": "docs/deletion.rst",
"chars": 3727,
"preview": "Deletion\n========\n\n.. versionadded:: 4.5.0\n\nThere is nothing special about deleting polymorphic models. The same rules a"
},
{
"path": "docs/formsets.rst",
"chars": 1747,
"preview": "Formsets\n========\n\n.. versionadded:: 1.0\n\nPolymorphic models can be used in formsets.\n\nThe implementation is almost iden"
},
{
"path": "docs/index.rst",
"chars": 4539,
"preview": "django-polymorphic\n==================\n\n.. only:: html\n\n .. image:: https://img.shields.io/badge/License-BSD-blue.svg\n "
},
{
"path": "docs/integrations/drf.rst",
"chars": 4096,
"preview": ".. _django-rest-framework-support:\n\n===================\ndjangorestframework\n===================\n\nPolymorphic serializers"
},
{
"path": "docs/integrations/index.rst",
"chars": 7204,
"preview": ".. _integrations:\n\nIntegrations\n============\n\nWhen integrating polymorphic models into third party apps you have three p"
},
{
"path": "docs/managers.rst",
"chars": 4657,
"preview": "Managers & Querysets\n====================\n\nUsing a Custom Manager\n----------------------\n\nA nice feature of Django is th"
},
{
"path": "docs/migrating.rst",
"chars": 2729,
"preview": "Migrating Existing Models\n=========================\n\nExisting models can be migrated to become polymorphic models. Durin"
},
{
"path": "docs/performance.rst",
"chars": 4131,
"preview": ".. _performance:\n\nPerformance Considerations\n==========================\n\nUsually, when Django users create their own pol"
},
{
"path": "docs/quickstart.rst",
"chars": 3631,
"preview": "Quickstart\n===========\n\nInstall the project using::\n\n pip install django-polymorphic\n\nUpdate the settings file:\n\n.. c"
},
{
"path": "docs/typing.rst",
"chars": 3716,
"preview": "Type Hints\n==========\n\n.. versionadded:: 4.11\n\n:pypi:`django-polymorphic` is now fully typed, and ships with type hints "
},
{
"path": "docs/views.rst",
"chars": 2123,
"preview": ".. _views:\n\nClass Based Views\n=================\n\nWhile :pypi:`django-polymorphic` provides full admin integration, you m"
},
{
"path": "example/example/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/example/settings.py",
"chars": 2985,
"preview": "import os\n\nDEBUG = True\n\nADMINS = (\n # ('Your Name', 'your_email@example.com'),\n)\n\nMANAGERS = ADMINS\nPROJECT_ROOT = o"
},
{
"path": "example/example/urls.py",
"chars": 286,
"preview": "from django.contrib import admin\nfrom django.urls import path, reverse_lazy\nfrom django.views.generic import RedirectVie"
},
{
"path": "example/example/wsgi.py",
"chars": 1139,
"preview": "\"\"\"\nWSGI config for example project.\n\nThis module contains the WSGI application used by Django's development server\nand "
},
{
"path": "example/manage.py",
"chars": 403,
"preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
},
{
"path": "example/orders/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/orders/admin.py",
"chars": 1096,
"preview": "from django.contrib import admin\n\nfrom polymorphic.admin import PolymorphicInlineSupportMixin, StackedPolymorphicInline\n"
},
{
"path": "example/orders/migrations/0001_initial.py",
"chars": 5200,
"preview": "from django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n dependencies = [(\"contenttypes\", "
},
{
"path": "example/orders/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/orders/models.py",
"chars": 1914,
"preview": "from django.db import models\nfrom django.utils.dates import MONTHS_3\nfrom django.utils.translation import gettext_lazy a"
},
{
"path": "example/pexp/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/pexp/admin.py",
"chars": 1545,
"preview": "from django.contrib import admin\nfrom pexp.models import *\n\nfrom polymorphic.admin import (\n PolymorphicChildModelAdm"
},
{
"path": "example/pexp/dumpdata_test_correct_output.txt",
"chars": 786,
"preview": "[\n {\n \"pk\": 1,\n \"model\": \"pexp.project\",\n \"fields\": {\n \"topic\": \"John's gathering\",\n "
},
{
"path": "example/pexp/management/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/pexp/management/commands/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/pexp/management/commands/p2cmd.py",
"chars": 3438,
"preview": "\"\"\"\nThis module is a scratchpad for general development, testing & debugging\nWell, even more so than pcmd.py. You best i"
},
{
"path": "example/pexp/management/commands/pcmd.py",
"chars": 966,
"preview": "\"\"\"\nThis module is a scratchpad for general development, testing & debugging.\n\"\"\"\n\nfrom django.core.management.base impo"
},
{
"path": "example/pexp/management/commands/polybench.py",
"chars": 2747,
"preview": "\"\"\"\nThis module is a scratchpad for general development, testing & debugging\n\"\"\"\n\nimport sys\nimport time\nfrom pprint imp"
},
{
"path": "example/pexp/management/commands/polymorphic_create_test_data.py",
"chars": 561,
"preview": "\"\"\"\nThis module is a scratchpad for general development, testing & debugging\n\"\"\"\n\nfrom django.core.management import Bas"
},
{
"path": "example/pexp/migrations/0001_initial.py",
"chars": 9915,
"preview": "from django.db import migrations, models\n\nimport polymorphic.showfields\n\n\nclass Migration(migrations.Migration):\n\n de"
},
{
"path": "example/pexp/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "example/pexp/models.py",
"chars": 2048,
"preview": "from django.db import models\n\nfrom polymorphic.models import PolymorphicModel\nfrom polymorphic.showfields import ShowFie"
},
{
"path": "justfile",
"chars": 11003,
"preview": "set windows-shell := [\"powershell.exe\", \"-NoLogo\", \"-Command\"]\nset unstable := true\nset script-interpreter := ['uv', 'ru"
},
{
"path": "manage.py",
"chars": 284,
"preview": "# This helps pytest-django locate the project.\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n os.environ.setdefaul"
},
{
"path": "pyproject.toml",
"chars": 7520,
"preview": "[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"django-polymorphic\"\nversion"
},
{
"path": "src/polymorphic/__init__.py",
"chars": 1406,
"preview": "r\"\"\"\n::\n\n ██████╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ██████╗\n ██╔══██╗ ██║██╔"
},
{
"path": "src/polymorphic/admin/__init__.py",
"chars": 1459,
"preview": "\"\"\"\nModelAdmin code to display polymorphic models.\n\nThe admin consists of a parent admin (which shows in the admin with "
},
{
"path": "src/polymorphic/admin/childadmin.py",
"chars": 11286,
"preview": "\"\"\"\nThe child admin displays the change/delete view of the subclass model.\n\"\"\"\n\nfrom __future__ import annotations\n\nimpo"
},
{
"path": "src/polymorphic/admin/filters.py",
"chars": 1765,
"preview": "from __future__ import annotations\n\nfrom collections.abc import Iterable\nfrom typing import Any, cast\n\nfrom django.contr"
},
{
"path": "src/polymorphic/admin/forms.py",
"chars": 726,
"preview": "from typing import Any\n\nfrom django import forms\nfrom django.contrib.admin.widgets import AdminRadioSelect\nfrom django.u"
},
{
"path": "src/polymorphic/admin/generic.py",
"chars": 3217,
"preview": "from __future__ import annotations\n\nfrom typing import Any, cast\n\nfrom django.contrib.contenttypes.admin import GenericI"
},
{
"path": "src/polymorphic/admin/helpers.py",
"chars": 6230,
"preview": "\"\"\"\nRendering utils for admin forms;\n\nThis makes sure that admin fieldsets/layout settings are exported to the template."
},
{
"path": "src/polymorphic/admin/inlines.py",
"chars": 12198,
"preview": "\"\"\"\nDjango Admin support for polymorphic inlines.\n\nEach row in the inline can correspond with a different subclass.\n\"\"\"\n"
},
{
"path": "src/polymorphic/admin/parentadmin.py",
"chars": 13629,
"preview": "\"\"\"\nThe parent admin displays the list view of the base model.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom typing impo"
},
{
"path": "src/polymorphic/apps.py",
"chars": 3137,
"preview": "from typing import Any, Iterable, Sequence\n\nfrom django.apps import AppConfig, apps\nfrom django.core.checks import Check"
},
{
"path": "src/polymorphic/base.py",
"chars": 9727,
"preview": "\"\"\"\nPolymorphicModel Meta Class\n\"\"\"\n\nimport sys\nimport warnings\nfrom typing import Any, cast\n\nfrom django.db import mode"
},
{
"path": "src/polymorphic/contrib/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/contrib/drf/LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2017, Denis Orehovsky\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "src/polymorphic/contrib/drf/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/contrib/drf/serializers.py",
"chars": 6627,
"preview": "from collections.abc import Mapping\n\nfrom django.core.exceptions import ImproperlyConfigured\nfrom django.db import model"
},
{
"path": "src/polymorphic/contrib/extra_views.py",
"chars": 4524,
"preview": "\"\"\"\nThe ``extra_views.formsets`` provides a simple way to handle formsets.\nThe ``extra_views.advanced`` provides a metho"
},
{
"path": "src/polymorphic/contrib/guardian.py",
"chars": 829,
"preview": "from typing import Any\n\nfrom django.contrib.contenttypes.models import ContentType\n\nfrom ..models import PolymorphicMode"
},
{
"path": "src/polymorphic/deletion.py",
"chars": 4896,
"preview": "\"\"\"\nClasses and utilities for handling deletions in polymorphic models.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom co"
},
{
"path": "src/polymorphic/formsets/__init__.py",
"chars": 1392,
"preview": "\"\"\"\nThis allows creating formsets where each row can be a different form type.\nThe logic of the formsets work similar to"
},
{
"path": "src/polymorphic/formsets/generic.py",
"chars": 4945,
"preview": "from __future__ import annotations\n\nfrom collections.abc import Callable, Iterable\nfrom typing import Any, cast\n\nfrom dj"
},
{
"path": "src/polymorphic/formsets/models.py",
"chars": 20295,
"preview": "from __future__ import annotations\n\nfrom collections import OrderedDict\nfrom collections.abc import Callable, Iterable\nf"
},
{
"path": "src/polymorphic/formsets/utils.py",
"chars": 358,
"preview": "\"\"\"\nInternal utils\n\"\"\"\n\nfrom django.forms import Media\n\n\ndef add_media(dest: Media, media: Media) -> None:\n \"\"\"\n O"
},
{
"path": "src/polymorphic/locale/en/LC_MESSAGES/django.po",
"chars": 711,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "src/polymorphic/locale/es/LC_MESSAGES/django.po",
"chars": 754,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "src/polymorphic/locale/fr/LC_MESSAGES/django.po",
"chars": 889,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "src/polymorphic/managers.py",
"chars": 15105,
"preview": "\"\"\"\nThe manager class for use in the models.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Iterab"
},
{
"path": "src/polymorphic/models.py",
"chars": 11428,
"preview": "\"\"\"\nSeamless Polymorphic Inheritance for Django Models\n\"\"\"\n\nfrom __future__ import annotations\n\nimport warnings\nfrom col"
},
{
"path": "src/polymorphic/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/query.py",
"chars": 30962,
"preview": "\"\"\"\nQuerySet for PolymorphicModel\n\"\"\"\n\nfrom __future__ import annotations\n\nimport copy\nimport heapq\nfrom collections imp"
},
{
"path": "src/polymorphic/query_translate.py",
"chars": 10881,
"preview": "\"\"\"\nPolymorphicQuerySet support functions\n\"\"\"\n\nimport copy\nfrom functools import reduce\nfrom operator import or_\nfrom ty"
},
{
"path": "src/polymorphic/related_descriptors.py",
"chars": 1744,
"preview": "from typing import Any, cast\n\nfrom django.db.models import QuerySet\nfrom django.db.models.fields.related_descriptors imp"
},
{
"path": "src/polymorphic/showfields.py",
"chars": 6646,
"preview": "import re\nfrom typing import TYPE_CHECKING, ClassVar\n\nfrom django.db import models\n\nif TYPE_CHECKING:\n from polymorph"
},
{
"path": "src/polymorphic/static/polymorphic/css/polymorphic_inlines.css",
"chars": 768,
"preview": ".polymorphic-add-choice {\n position: relative;\n clear: left;\n}\n\n.polymorphic-add-choice a:focus {\n text-decoration: n"
},
{
"path": "src/polymorphic/static/polymorphic/js/polymorphic_inlines.js",
"chars": 16313,
"preview": "/*global DateTimeShortcuts, SelectFilter*/\n\n// This is a slightly adapted version of Django's inlines.js\n// Forked for p"
},
{
"path": "src/polymorphic/templates/admin/polymorphic/add_type_form.html",
"chars": 291,
"preview": "{% extends \"admin/change_form.html\" %}\n\n{% if save_on_top %}\n {% block submit_buttons_top %}\n {% include 'admin/subm"
},
{
"path": "src/polymorphic/templates/admin/polymorphic/change_form.html",
"chars": 190,
"preview": "{% extends \"admin/change_form.html\" %}\n{% load polymorphic_admin_tags %}\n\n{% block breadcrumbs %}\n {% breadcrumb_scope "
},
{
"path": "src/polymorphic/templates/admin/polymorphic/delete_confirmation.html",
"chars": 198,
"preview": "{% extends \"admin/delete_confirmation.html\" %}\n{% load polymorphic_admin_tags %}\n\n{% block breadcrumbs %}\n {% breadcrum"
},
{
"path": "src/polymorphic/templates/admin/polymorphic/edit_inline/stacked.html",
"chars": 2359,
"preview": "{% load i18n admin_urls static %}\n\n<div class=\"js-inline-polymorphic-admin-formset inline-group\"\n id=\"{{ inline_admi"
},
{
"path": "src/polymorphic/templates/admin/polymorphic/object_history.html",
"chars": 193,
"preview": "{% extends \"admin/object_history.html\" %}\n{% load polymorphic_admin_tags %}\n\n{% block breadcrumbs %}\n {% breadcrumb_sco"
},
{
"path": "src/polymorphic/templatetags/__init__.py",
"chars": 115,
"preview": "\"\"\"\nWe provide collections of tags that override or extend template tags for formsets and\nthe admin interface.\n\"\"\"\n"
},
{
"path": "src/polymorphic/templatetags/polymorphic_admin_tags.py",
"chars": 2536,
"preview": "from django.template import Context, Library, Node, NodeList, TemplateSyntaxError\nfrom django.template.base import Filte"
},
{
"path": "src/polymorphic/templatetags/polymorphic_formset_tags.py",
"chars": 5125,
"preview": "\"\"\"\n.. versionadded:: 1.1\n\nTo render formsets in the frontend, the ``polymorphic_tags`` provides extra\nfilters to implem"
},
{
"path": "src/polymorphic/tests/__init__.py",
"chars": 16,
"preview": "HEADLESS = True\n"
},
{
"path": "src/polymorphic/tests/admin.py",
"chars": 5504,
"preview": "from inspect import isclass\nfrom django.contrib.admin import register, ModelAdmin, TabularInline, site as admin_site\nfro"
},
{
"path": "src/polymorphic/tests/admintestcase.py",
"chars": 8628,
"preview": "from django.conf import settings\nfrom django.contrib.admin import AdminSite\nfrom django.contrib.admin.templatetags.admin"
},
{
"path": "src/polymorphic/tests/conftest.py",
"chars": 515,
"preview": "from __future__ import annotations\n\nimport pathlib\nimport pytest\n\nINTEGRATION_DIR = pathlib.Path(__file__).resolve().par"
},
{
"path": "src/polymorphic/tests/debug.py",
"chars": 38,
"preview": "from .settings import *\n\nDEBUG = True\n"
},
{
"path": "src/polymorphic/tests/deletion/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/deletion/migrations/0001_initial.py",
"chars": 38374,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom decimal import Decimal\nfrom django.conf import settings\nfrom django."
},
{
"path": "src/polymorphic/tests/deletion/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/deletion/models.py",
"chars": 10329,
"preview": "from django.db import models\nfrom django.conf import settings\nfrom polymorphic.models import PolymorphicModel\nfrom polym"
},
{
"path": "src/polymorphic/tests/deletion/test_deletion.py",
"chars": 32013,
"preview": "from django.test import TestCase\nimport shutil\nimport tempfile\nfrom django.contrib.auth import get_user_model\nfrom djang"
},
{
"path": "src/polymorphic/tests/errata/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/errata/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/errata/models.py",
"chars": 906,
"preview": "from polymorphic.models import PolymorphicModel\nfrom polymorphic.managers import PolymorphicManager\nfrom django.db impor"
},
{
"path": "src/polymorphic/tests/errata/settings.py",
"chars": 100,
"preview": "from ..settings import *\n\nINSTALLED_APPS = [\n *INSTALLED_APPS,\n \"polymorphic.tests.errata\",\n]\n"
},
{
"path": "src/polymorphic/tests/errata/test_errata.py",
"chars": 2791,
"preview": "from django.core.checks import Error, run_checks\nfrom django.test.utils import override_settings\nfrom django.test import"
},
{
"path": "src/polymorphic/tests/examples/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/apps.py",
"chars": 202,
"preview": "from django.apps import AppConfig\n\n\nclass IntegrationsExampleConfig(AppConfig):\n name = \"polymorphic.tests.examples.i"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/apps.py",
"chars": 188,
"preview": "from django.apps import AppConfig\n\n\nclass DRFExampleConfig(AppConfig):\n name = \"polymorphic.tests.examples.integratio"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/example_serializers.py",
"chars": 981,
"preview": "from rest_framework import serializers\n\nfrom polymorphic.contrib.drf.serializers import PolymorphicSerializer\n\nfrom .mod"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/filter_serializers.py",
"chars": 1048,
"preview": "from .models import AiModelAnnotator, UserAnnotator, Annotator, Data\nfrom rest_framework import serializers\nfrom polymor"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/filter_views.py",
"chars": 1090,
"preview": "from .filter_serializers import AnnotationSerializer\nfrom .models import Data, AiModelAnnotator\nfrom rest_framework impo"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/migrations/0001_initial.py",
"chars": 6075,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.conf import settings\nfrom django.db import migrations, models"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/models/__init__.py",
"chars": 444,
"preview": "from .models_test import BlogBase, BlogOne, BlogTwo, BlogThree\nfrom .example_models import (\n Project,\n ArtProject"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/models/example_models.py",
"chars": 314,
"preview": "from django.db import models\n\nfrom polymorphic.models import PolymorphicModel\n\n\nclass Project(PolymorphicModel):\n top"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/models/filters.py",
"chars": 627,
"preview": "\"\"\"\nhttps://github.com/jazzband/django-polymorphic/issues/520\n\"\"\"\n\nfrom polymorphic.models import PolymorphicModel\nfrom "
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/models/models_test.py",
"chars": 502,
"preview": "from django.db import models\n\nfrom polymorphic.models import PolymorphicModel\n\n\nclass BlogBase(PolymorphicModel):\n na"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/serializers.py",
"chars": 967,
"preview": "from rest_framework import serializers\n\nfrom polymorphic.contrib.drf.serializers import PolymorphicSerializer\n\nfrom .mod"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/test.py",
"chars": 26851,
"preview": "from django.core.exceptions import ImproperlyConfigured\n\nimport pytest\n\ntry:\n from rest_framework import serializers\n"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/urls.py",
"chars": 311,
"preview": "from rest_framework.routers import DefaultRouter\n\nfrom .views import ProjectViewSet\nfrom .filter_views import Annotation"
},
{
"path": "src/polymorphic/tests/examples/integrations/drf/views.py",
"chars": 263,
"preview": "from rest_framework import viewsets\n\nfrom .models import Project\nfrom .example_serializers import ProjectPolymorphicSeri"
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/apps.py",
"chars": 229,
"preview": "from django.apps import AppConfig\n\n\nclass ExtraViewsExampleConfig(AppConfig):\n name = \"polymorphic.tests.examples.int"
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/templates/extra_views/article_formset.html",
"chars": 498,
"preview": "{% load extra_views_tags %}\n<!DOCTYPE html>\n<html>\n<head>\n <title>Article Formset</title>\n</head>\n<body>\n <h1>Arti"
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/templatetags/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/templatetags/extra_views_tags.py",
"chars": 202,
"preview": "from django import template\n\nregister = template.Library()\n\n\n@register.filter\ndef model_name(instance):\n \"\"\"Get the m"
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/test.py",
"chars": 23574,
"preview": "from unittest import skipUnless\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.test import TestC"
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/urls.py",
"chars": 182,
"preview": "from django.urls import path\nfrom .views import ArticleFormSetView\n\napp_name = \"extra_views\"\n\nurlpatterns = [\n path(\""
},
{
"path": "src/polymorphic/tests/examples/integrations/extra_views/views.py",
"chars": 737,
"preview": "from polymorphic.contrib.extra_views import PolymorphicFormSetView\nfrom polymorphic.formsets import PolymorphicFormSetCh"
},
{
"path": "src/polymorphic/tests/examples/integrations/guardian/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/guardian/apps.py",
"chars": 230,
"preview": "from django.apps import AppConfig\n\n\nclass GuardianExampleConfig(AppConfig):\n name = \"polymorphic.tests.examples.integ"
},
{
"path": "src/polymorphic/tests/examples/integrations/guardian/test.py",
"chars": 8937,
"preview": "from unittest import skipUnless\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.contenttypes.models i"
},
{
"path": "src/polymorphic/tests/examples/integrations/migrations/0001_initial.py",
"chars": 1962,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.db import migrations, models\nimport django.db.models.deletion"
},
{
"path": "src/polymorphic/tests/examples/integrations/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/models.py",
"chars": 443,
"preview": "from django.db import models\nfrom polymorphic.models import PolymorphicModel\n\n\nclass Article(PolymorphicModel):\n titl"
},
{
"path": "src/polymorphic/tests/examples/integrations/reversion/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/integrations/reversion/admin.py",
"chars": 884,
"preview": "from django.contrib import admin\nfrom polymorphic.admin import (\n PolymorphicParentModelAdmin,\n PolymorphicChildMo"
},
{
"path": "src/polymorphic/tests/examples/integrations/reversion/apps.py",
"chars": 223,
"preview": "from django.apps import AppConfig\n\n\nclass ReversionExampleConfig(AppConfig):\n name = \"polymorphic.tests.examples.inte"
},
{
"path": "src/polymorphic/tests/examples/integrations/reversion/templates/admin/polymorphic/object_history.html",
"chars": 199,
"preview": "{% extends 'reversion/object_history.html' %}\n{% load polymorphic_admin_tags %}\n\n{% block breadcrumbs %}\n {% breadcru"
},
{
"path": "src/polymorphic/tests/examples/integrations/reversion/test.py",
"chars": 22686,
"preview": "from unittest import skipUnless\nfrom django.test import TestCase\nfrom django.urls import reverse\nfrom playwright.sync_ap"
},
{
"path": "src/polymorphic/tests/examples/type_hints/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/apps.py",
"chars": 206,
"preview": "from django.apps import AppConfig\n\n\nclass TypeHintsFKConfig(AppConfig):\n name = \"polymorphic.tests.examples.type_hint"
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/migrations/0001_initial.py",
"chars": 2291,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.db import migrations, models\nimport django.db.models.deletion"
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/models.py",
"chars": 1576,
"preview": "from django.db import models\nfrom polymorphic.models import PolymorphicModel\nfrom polymorphic.managers import (\n Poly"
},
{
"path": "src/polymorphic/tests/examples/type_hints/fk/test.py",
"chars": 1445,
"preview": "import typing as t\nfrom typing_extensions import assert_type\nfrom django.test import TestCase\nfrom .models import Parent"
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/apps.py",
"chars": 201,
"preview": "from django.apps import AppConfig\n\n\nclass TypeHintsM2MConfig(AppConfig):\n name = \"polymorphic.tests.examples.type_hin"
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/migrations/0001_initial.py",
"chars": 3612,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.db import migrations, models\nimport django.db.models.deletion"
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/models.py",
"chars": 2282,
"preview": "from __future__ import annotations\nfrom typing import ClassVar\nfrom django.db import models\nfrom polymorphic.models impo"
},
{
"path": "src/polymorphic/tests/examples/type_hints/m2m/test.py",
"chars": 2742,
"preview": "import typing as t\nfrom django.test import TestCase\nfrom django.db import models\n\n# from django.db import models\nfrom .m"
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/apps.py",
"chars": 221,
"preview": "from django.apps import AppConfig\n\n\nclass TypeHintsManagersConfig(AppConfig):\n name = \"polymorphic.tests.examples.typ"
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/migrations/0001_initial.py",
"chars": 1692,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.db import migrations, models\nimport django.db.models.deletion"
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/models.py",
"chars": 904,
"preview": "from __future__ import annotations\nimport typing as t\nfrom typing_extensions import Self\nfrom polymorphic.models import "
},
{
"path": "src/polymorphic/tests/examples/type_hints/managers/test.py",
"chars": 3098,
"preview": "import typing as t\nfrom django.test import TestCase\nfrom .models import ParentModel, Child1, Child2\n\n\nclass TypeHintsMan"
},
{
"path": "src/polymorphic/tests/examples/type_hints/models.py",
"chars": 2187,
"preview": "# from __future__ import annotations\n# import typing as t\n# from typing_extensions import Self\n# from django.db import m"
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/apps.py",
"chars": 217,
"preview": "from django.apps import AppConfig\n\n\nclass TypeHintsOne2OneConfig(AppConfig):\n name = \"polymorphic.tests.examples.type"
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/migrations/0001_initial.py",
"chars": 2334,
"preview": "# Generated by Django 4.2 on 2026-02-05 14:47\n\nfrom django.db import migrations, models\nimport django.db.models.deletion"
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/migrations/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/models.py",
"chars": 1578,
"preview": "from django.db import models\nfrom polymorphic.models import PolymorphicModel\nfrom polymorphic.managers import (\n Poly"
},
{
"path": "src/polymorphic/tests/examples/type_hints/one2one/test.py",
"chars": 1680,
"preview": "import typing as t\nfrom django.db.models.fields.reverse_related import OneToOneRel\nfrom typing_extensions import assert_"
}
]
// ... and 40 more files (download for full content)
About this extraction
This page contains the full source code of the chrisglass/django_polymorphic GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 240 files (1.2 MB), approximately 289.3k tokens, and a symbol index with 1405 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.