add justfile interface for command package management tasks, lint docs, change precommit to use just interface and update lint GHA accordingly

This commit is contained in:
Brian Kohan 2025-08-24 17:33:58 -07:00
parent 0dc5327a0f
commit e5caa70e59
No known key found for this signature in database
GPG Key ID: 827B6A3B1AAE16EE
17 changed files with 768 additions and 475 deletions

View File

@ -1,4 +0,0 @@
[run]
source = polymorphic/
omit =
*/migrations/*

View File

@ -1,19 +1,88 @@
name: Lint
permissions:
contents: read
on:
push:
tags-ignore:
- '*'
branches:
- master
tags:
- 'v*'
- '*'
pull_request:
branches:
- master
workflow_call:
workflow_dispatch:
inputs:
debug:
description: 'Open ssh debug session.'
required: true
default: false
type: boolean
jobs:
Lint:
linting:
runs-on: ubuntu-latest
strategy:
matrix:
# run static analysis on bleeding and trailing edges
python-version: [ '3.9', '3.10', '3.13' ]
django-version:
- '3.2' # LTS April 2024
- '4.2' # LTS April 2026
- '5.2' # December 2025
exclude:
- python-version: '3.9'
django-version: '4.2'
- python-version: '3.13'
django-version: '4.2'
- python-version: '3.13'
django-version: '3.2'
- python-version: '3.10'
django-version: '3.2'
- python-version: '3.9'
django-version: '5.2'
- python-version: '3.10'
django-version: '5.2'
env:
TEST_PYTHON_VERSION: ${{ matrix.python-version }}
TEST_DJANGO_VERSION: ${{ matrix.django-version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v5
with:
python-version: "3.13"
- uses: pre-commit/action@v3.0.1
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
id: sp
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install Just
uses: extractions/setup-just@v3
- name: Install Dependencies
run: |
just setup ${{ steps.sp.outputs.python-path }}
uv add Django~=${{ matrix.django-version }}.0
just install-docs
- 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@v3.22
with:
detached: true
timeout-minutes: 60
- name: Run Static Analysis
run: |
just check-lint
just check-format
just check-types
just check-package
just check-readme

230
.gitignore vendored
View File

@ -1,20 +1,218 @@
*.pyc
*.pyo
*.mo
*.db
*.egg-info/
*.egg/
.coverage
coverage.xml
.project
.idea/
.pydevproject
.idea/workspace.xml
.tox/
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
docs/_build/
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
# 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/
.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

View File

@ -1,15 +1,13 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
- repo: local
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.9
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
exclude: '.*migrations.*'
- id: lint
name: Lint
entry: just lint
language: system
pass_filenames: false
- id: format
name: Format
entry: just format
language: system
pass_filenames: false

View File

@ -1,16 +1,24 @@
# Read the Docs configuration file for Sphinx projects
# .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"
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
python:
install:
- requirements: docs/_ext/djangodummy/requirements.txt
configuration: docs/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
formats:
- pdf

View File

@ -14,23 +14,87 @@ We are actively seeking additional maintainers. If you're interested, [contact m
We provide a platform independent justfile with recipes for all the development tasks. You should [install just](https://just.systems/man/en/installation.html) 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:
[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:
```shell
```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
TODO
`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 install-docs # install the doc dependencies
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
TODO
`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
```
## Running Tests
TODO
`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
```
## Versioning
@ -47,5 +111,40 @@ 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-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 static type checking
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
docs # build and open the documentation
docs-live # serve the documentation, with auto-reload
fetch-refs LIB
fix # fix formatting, linting issues and import sorting
format # format the code and sort imports
install *OPTS # update and install development dependencies
install-docs # install documentation 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)
run +ARGS # run the command in the virtual environment
setup python="python" # setup the venv and pre-commit hooks
sort-imports # sort the python imports
test *TESTS # run tests
validate_version VERSION # validate the given version string against the lib version
```

View File

@ -1,153 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-polymorphic.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-polymorphic.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/django-polymorphic"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-polymorphic"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@ -9,18 +9,22 @@ Setup
Both the parent model and child model need to have a ``ModelAdmin`` class.
The shared base model should use the :class:`~polymorphic.admin.PolymorphicParentModelAdmin` as base 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.
: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`
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``.
This only happens when :attr:`~polymorphic.admin.PolymorphicChildModelAdmin.show_in_index` is set to
``True``.
Fieldset configuration
~~~~~~~~~~~~~~~~~~~~~~
@ -41,11 +45,12 @@ Hence, the fieldset configuration should be placed on the child admin.
.. versionchanged:: 1.0
It's now needed to register the child model classes too.
In *django-polymorphic* 0.9 and below, the ``child_models`` was a tuple of a ``(Model, ChildModelAdmin)``.
The admin classes were registered in an internal class, and kept away from the main admin site.
This caused various subtle problems with the ``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.
In *django-polymorphic* 0.9 and below, the ``child_models`` was a tuple of a
``(Model, ChildModelAdmin)``. The admin classes were registered in an internal class, and kept
away from the main admin site. This caused various subtle problems with the ``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:
@ -98,8 +103,9 @@ The models are taken from :ref:`advanced-features`.
Filtering child types
---------------------
Child model types can be filtered by adding a :class:`~polymorphic.admin.PolymorphicChildModelFilter`
to the ``list_filter`` attribute. See the example above.
Child model types can be filtered by adding a
:class:`~polymorphic.admin.PolymorphicChildModelFilter` to the ``list_filter`` attribute. See the
example above.
Inline models
@ -109,7 +115,8 @@ Inline models
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.
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.
@ -168,9 +175,10 @@ The child classes can be nested for clarity, but this is not a requirement.
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 ``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 AttributeError with the message "can't set attribute".
To add a polymorphic child model as an Inline for another model, add a field to the inline's
``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
AttributeError with the message "can't set attribute".
.. code-block:: python
@ -200,16 +208,19 @@ The polymorphic admin interface works in a simple way:
* 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 ``ModelAdmin`` of the derived child model. The *list* page is still implemented by the parent model admin.
to the ``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:
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.
: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, ``child_models`` is the best solution.
@ -222,7 +233,8 @@ the performance hit of retrieving child models.
This can be controlled by setting the ``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:`third-party`.
If you use other applications such as django-reversion_ or django-mptt_, please check
+:ref:`third-party`.
Note: If you are using non-integer primary keys in your model, you have to edit ``pk_regex``,
for example ``pk_regex = '([\w-]+)'`` if you use UUIDs. Otherwise you cannot change model entries.
@ -230,16 +242,21 @@ for example ``pk_regex = '([\w-]+)'`` if you use UUIDs. Otherwise you cannot cha
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:
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.
* 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.
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

View File

@ -44,7 +44,8 @@ v3.1.0 (2021-11-18)
* 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 ``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.
@ -75,14 +76,16 @@ v2.1 (2019-07-15)
-----------------
* Added Django 2.2 support.
* Changed ``.non_polymorphic()``, to use a different iterable class that completely cirvumvent polymorphic.
* 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 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.
@ -98,8 +101,9 @@ v2.0.3 (2018-08-24)
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 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.
@ -123,8 +127,8 @@ v2.0.0 (2018-01-22)
* **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.
* 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.
@ -177,7 +181,8 @@ 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 Django 1.11 accessor checks (to support subclasses of ``ForwardManyToOneDescriptor``, like
``ForwardOneToOneDescriptor``)
* Fixed polib syntax error messages in translations.
@ -210,7 +215,8 @@ v1.0.2 (2016-10-14)
* 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.
* Fixed ``ParentAdminNotRegistered`` exception for models that are registered via a proxy model
instead of the real base model.
v1.0.1 (2016-09-11)
@ -226,7 +232,8 @@ v1.0.0 (2016-09-02)
* 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.
* Added support for multiple databases with the ``.using()`` method and ``using=..`` keyword
argument.
* Fixed modifying passed ``Q()`` objects in place.
.. note::
@ -235,8 +242,8 @@ v1.0.0 (2016-09-02)
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.
* 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.
@ -260,8 +267,9 @@ 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 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
@ -278,15 +286,16 @@ v0.9.0 (2016-02-17)
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 :ref:`django-reversion-compare support <django-reversion-compare-support>`.
* Fix missing ``history_view()`` redirection to the child admin, which is important for
django-reversion_ support. See the documentation for hints for
:ref:`django-reversion-compare support <django-reversion-compare-support>`.
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``).
* 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)
@ -304,7 +313,8 @@ v0.8.0 (2015-12-28)
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 ``__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:
@ -322,7 +332,8 @@ 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.
* 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.
@ -338,9 +349,11 @@ 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="...")``.
* 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 ``_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)
@ -350,8 +363,8 @@ 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 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
@ -360,15 +373,17 @@ 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.
* **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_).
* Fixed passing ``?ct_id=`` to the add view for Django 1.6 (fixes compatibility with
django-parler_).
v0.5.5 (2014-04-29)
@ -380,7 +395,8 @@ v0.5.5 (2014-04-29)
v0.5.4 (2014-04-09)
-------------------
* Fix ``.non_polymorphic()`` to returns a clone of the queryset, instead of effecting the existing queryset.
* 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.
@ -432,7 +448,8 @@ v0.4.1 (2013-04-10)
* 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.
* **Deprecated** the ``queryset_class`` argument of the ``PolymorphicManager`` constructor, use the
class attribute instead.
* **Dropped** Django 1.1, 1.2 and 1.3 support

View File

@ -52,7 +52,7 @@ master_doc = "index"
# General information about the project.
project = "django-polymorphic"
copyright = "2013, Bert Constantin, Chris Glass, Diederik van der Boor"
copyright = "2013, Bert Constantin, Chris Glass, Diederik van der Boor, Brian Kohan"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@ -196,7 +196,7 @@ latex_documents = [
"index",
"django-polymorphic.tex",
"django-polymorphic Documentation",
"Bert Constantin, Chris Glass, Diederik van der Boor",
"Bert Constantin, Chris Glass, Diederik van der Boor, Brian Kohan",
"manual",
)
]
@ -231,7 +231,7 @@ man_pages = [
"index",
"django-polymorphic",
"django-polymorphic Documentation",
["Bert Constantin, Chris Glass, Diederik van der Boor"],
["Bert Constantin, Chris Glass, Diederik van der Boor", "Brian Kohan"],
1,
)
]
@ -250,7 +250,7 @@ texinfo_documents = [
"index",
"django-polymorphic",
"django-polymorphic Documentation",
"Bert Constantin, Chris Glass, Diederik van der Boor",
"Bert Constantin, Chris Glass, Diederik van der Boor, Brian Kohan",
"django-polymorphic",
"One line description of project.",
"Miscellaneous",

View File

@ -33,7 +33,8 @@ Like standard Django 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.
* :func:`~polymorphic.formsets.generic_polymorphic_inlineformset_factory` - create an inline formset
for a generic foreign key.
Each one uses a different base class:
@ -41,4 +42,5 @@ Each one uses a different base class:
* :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.
When needed, the base class can be overwritten and provided to the factory via the ``formset``
parameter.

View File

@ -1,190 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-polymorphic.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-polymorphic.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@ -60,9 +60,11 @@ Use ``instance_of`` or ``not_instance_of`` for narrowing the result to specific
Polymorphic filtering: Get all projects where Mr. Turner is involved as an artist
or supervisor (note the three underscores):
>>> Project.objects.filter(Q(ArtProject___artist='T. Turner') | Q(ResearchProject___supervisor='T. Turner'))
[ <ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
<ResearchProject: id 4, topic "Color Use in Late Cubism", supervisor "T. Turner"> ]
.. code-block:: python
>>> Project.objects.filter(Q(ArtProject___artist='T. Turner') | Q(ResearchProject___supervisor='T. Turner'))
[ <ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
<ResearchProject: id 4, topic "Color Use in Late Cubism", supervisor "T. Turner"> ]
This is basically all you need to know, as *django-polymorphic* mostly
works fully automatic and just delivers the expected results.

View File

@ -14,14 +14,16 @@ Add this option to your settings:
GUARDIAN_GET_CONTENT_TYPE = 'polymorphic.contrib.guardian.get_polymorphic_base_content_type'
This option requires django-guardian_ >= 1.4.6. Details about how this option works are available in the
`django-guardian documentation <https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type>`_.
This option requires django-guardian_ >= 1.4.6. Details about how this option works are available in
the `django-guardian documentation
<https://django-guardian.readthedocs.io/en/latest/configuration>`_.
django-rest-framework support
-----------------------------
The django-rest-polymorphic_ package provides polymorphic serializers that help you integrate your polymorphic models with `django-rest-framework`.
The django-rest-polymorphic_ package provides polymorphic serializers that help you integrate your
polymorphic models with `django-rest-framework`.
Example
@ -104,9 +106,12 @@ django-reversion support
Support for django-reversion_ works as expected with polymorphic models.
However, they require more setup than standard models. That's become:
* Manually register the child models with django-reversion_, so their ``follow`` parameter can be set.
* Polymorphic models use `multi-table inheritance <https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance>`_.
See the `reversion documentation <https://django-reversion.readthedocs.io/en/latest/api.html#multi-table-inheritance>`_
* Manually register the child models with django-reversion_, so their ``follow`` parameter can be
set.
* Polymorphic models use `multi-table inheritance
<https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance>`_.
See the `reversion documentation
<https://django-reversion.readthedocs.io/en/latest/api.html#registration-api>`_
how to deal with this by adding a ``follow`` field for the primary key.
* Both admin classes redefine ``object_history_template``.
@ -161,7 +166,8 @@ Redefine a :file:`admin/polymorphic/object_history.html` template, so it combine
{% breadcrumb_scope base_opts %}{{ block.super }}{% endbreadcrumb_scope %}
{% endblock %}
This makes sure both the reversion template is used, and the breadcrumb is corrected for the polymorphic model.
This makes sure both the reversion template is used, and the breadcrumb is corrected for the
polymorphic model.
.. _django-reversion-compare-support:
@ -180,7 +186,8 @@ In your parent admin, include the following method:
As the compare view resolves the the parent admin, it uses it's base model to find revisions.
This doesn't work, since it needs to look for revisions of the child model. Using this tweak,
the view of the actual child model is used, similar to the way the regular change and delete views are redirected.
the view of the actual child model is used, similar to the way the regular change and delete views
are redirected.
.. _django-extra-views: https://github.com/AndrewIngram/django-extra-views

219
justfile Normal file
View File

@ -0,0 +1,219 @@
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
set unstable := true
set script-interpreter := ['uv', 'run', '--script']
export PYTHONPATH := source_directory()
[private]
default:
@just --list --list-submodules
# run the django admin
[script]
manage *COMMAND:
import os
import sys
from django.core import management
sys.path.append(os.getcwd())
os.environ["DJANGO_SETTINGS_MODULE"] = "polymorphic.tests.settings"
management.execute_from_command_line(sys.argv + "{{ COMMAND }}".split(" "))
# install the uv package manager
[linux]
[macos]
install_uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
# install the uv package manager
[windows]
install_uv:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# setup the venv and pre-commit hooks
setup python="python":
uv venv -p {{ python }}
@just run pre-commit install
# install git pre-commit hooks
install-precommit:
@just run pre-commit install
# update and install development dependencies
install *OPTS:
uv sync {{ OPTS }}
@just run pre-commit install
# install documentation dependencies
install-docs:
uv sync --group docs --all-extras
# run static type checking
check-types:
#TODO @just run mypy src/polymorphic
# run package checks
check-package:
@just run pip check
# remove doc build artifacts-
[script]
clean-docs:
import shutil
shutil.rmtree('./docs/_build', ignore_errors=True)
# remove the virtual environment
[script]
clean-env:
import shutil
import sys
shutil.rmtree(".venv", ignore_errors=True)
# remove all git ignored files
clean-git-ignored:
git clean -fdX
# remove all non repository artifacts
clean: clean-docs clean-env clean-git-ignored
# build html documentation
build-docs-html: install-docs
@just run sphinx-build --fresh-env --builder html --doctree-dir ./docs/_build/doctrees ./docs/ ./docs/_build/html
# build pdf documentation
build-docs-pdf: install-docs
@just run sphinx-build --fresh-env --builder latex --doctree-dir ./docs/_build/doctrees ./docs/ ./docs/_build/pdf
cd docs/_build/pdf && make
# build the docs
build-docs: build-docs-html
# build docs and package
build: build-docs-html
uv build
# open the html documentation
[script]
open-docs:
import os
import webbrowser
webbrowser.open(f'file://{os.getcwd()}/docs/_build/html/index.html')
# build and open the documentation
docs: build-docs-html open-docs
# serve the documentation, with auto-reload
docs-live: install-docs
@just run sphinx-autobuild docs docs/_build --open-browser --watch src --port 8000 --delay 1
_link_check:
-uv run sphinx-build -b linkcheck -Q -D linkcheck_timeout=10 ./docs/ ./docs/_build
# check the documentation links for broken links
[script]
check-docs-links: _link_check
import os
import sys
import json
from pathlib import Path
# The json output isn't valid, so we have to fix it before we can process.
data = json.loads(f"[{','.join((Path(os.getcwd()) / 'docs/_build/output.json').read_text().splitlines())}]")
broken_links = [link for link in data if link["status"] not in {"working", "redirected", "unchecked", "ignored"}]
if broken_links:
for link in broken_links:
print(f"[{link['status']}] {link['filename']}:{link['lineno']} -> {link['uri']}", file=sys.stderr)
sys.exit(1)
# lint the documentation
check-docs:
@just run doc8 --ignore-path ./docs/_build --max-line-length 100 -q ./docs
# lint the code
check-lint:
@just run ruff check --select I
@just run ruff check
# check if the code needs formatting
check-format:
@just run ruff format --check
# check that the readme renders
check-readme:
@just run -m readme_renderer ./README.md -o /tmp/README.html
_check-readme-quiet:
@just --quiet check-readme
# sort the python imports
sort-imports:
@just run ruff check --fix --select I
# format the code and sort imports
format: sort-imports
just --fmt --unstable
@just run ruff format
# sort the imports and fix linting issues
lint: sort-imports
@just run ruff check --fix
# fix formatting, linting issues and import sorting
fix: lint format
# run all static checks
check: check-lint check-format check-types check-package check-docs check-docs-links _check-readme-quiet
# run tests
test *TESTS:
@just run pytest --cov-append {{ TESTS }}
# run the pre-commit checks
precommit:
@just run pre-commit
# generate the test coverage report
coverage:
@just run coverage combine --keep *.coverage
@just run coverage report
@just run coverage xml
[script]
fetch-refs LIB: install-docs
import os
from pathlib import Path
import logging as _logging
import sys
import runpy
from sphinx.ext.intersphinx import inspect_main
_logging.basicConfig()
libs = runpy.run_path(Path(os.getcwd()) / "docs/conf.py").get("intersphinx_mapping")
url = libs.get("{{ LIB }}", None)
if not url:
sys.exit(f"Unrecognized {{ LIB }}, must be one of: {', '.join(libs.keys())}")
if url[1] is None:
url = f"{url[0].rstrip('/')}/objects.inv"
else:
url = url[1]
raise SystemExit(inspect_main([url]))
# run the command in the virtual environment
run +ARGS:
uv run {{ ARGS }}
# validate the given version string against the lib version
[script]
validate_version VERSION:
import re
import tomllib
import polymorphic
version = re.match(r"v?(\d+[.]\d+[.]\w+)", "{{ VERSION }}").groups()[0]
assert version == tomllib.load(open('pyproject.toml', 'rb'))['project']['version']
assert version == polymorphic.__version__
print(version)
# issue a release for the given semver string (e.g. 2.1.0)
release VERSION:
@just validate_version v{{ VERSION }}
git tag -s v{{ VERSION }} -m "{{ VERSION }} Release"
git push origin v{{ VERSION }}

View File

@ -88,6 +88,10 @@ sphinx = true
[tool.ruff]
line-length = 99
exclude = [
"**/migrations/*.py",
"**/migrations/**",
]
[tool.ruff.lint]
extend-ignore = [
@ -132,9 +136,9 @@ addopts = [
[tool.coverage.run]
source = [
"polymorphic"
"src/polymorphic"
]
omit = ["*/tests/*", "src/polymorphic/tests/*"]
omit = ["*/migrations/*", "*/tests/*", "src/polymorphic/tests/*"]
branch = true
relative_files = true

View File

@ -3,12 +3,12 @@ from django.contrib.contenttypes.models import ContentType
def get_polymorphic_base_content_type(obj):
"""
Helper function to return the base polymorphic content type id. This should used with django-guardian and the
GUARDIAN_GET_CONTENT_TYPE option.
Helper function to return the base polymorphic content type id. This should used
with django-guardian and the ``GUARDIAN_GET_CONTENT_TYPE`` option.
See the django-guardian documentation for more information:
https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type
https://django-guardian.readthedocs.io/en/latest/configuration
"""
if hasattr(obj, "polymorphic_model_marker"):
try: