Add API documentation to the package!
parent
c76cc663e0
commit
f9fffc44c1
|
|
@ -0,0 +1,3 @@
|
|||
# for readthedocs
|
||||
# Remaining requirements are picked up from setup.py
|
||||
Django==1.5.10
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# 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'
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
Automatically mention all model fields as parameters in the model construction.
|
||||
Based on http://djangosnippets.org/snippets/2533/
|
||||
"""
|
||||
import django
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.encoding import force_unicode
|
||||
import inspect
|
||||
|
||||
|
||||
def improve_model_docstring(app, what, name, obj, options, lines):
|
||||
from django.db import models # must be inside the function, to allow settings initialization first.
|
||||
|
||||
if inspect.isclass(obj) and issubclass(obj, models.Model):
|
||||
if django.VERSION >= (1,8):
|
||||
model_fields = obj._meta.get_fields()
|
||||
elif django.VERSION >= (1,6):
|
||||
model_fields = obj._meta.fields
|
||||
else:
|
||||
model_fields = obj._meta._fields()
|
||||
|
||||
for field in model_fields:
|
||||
help_text = strip_tags(force_unicode(field.help_text))
|
||||
verbose_name = force_unicode(field.verbose_name).capitalize()
|
||||
|
||||
# Add parameter
|
||||
if help_text:
|
||||
lines.append(u':param %s: %s' % (field.attname, help_text))
|
||||
else:
|
||||
lines.append(u':param %s: %s' % (field.attname, verbose_name))
|
||||
|
||||
# Add type
|
||||
if isinstance(field, models.ForeignKey):
|
||||
to = field.rel.to
|
||||
lines.append(u':type %s: %s to :class:`~%s.%s`' % (field.attname, type(field).__name__, to.__module__, to.__name__))
|
||||
else:
|
||||
lines.append(u':type %s: %s' % (field.attname, type(field).__name__))
|
||||
|
||||
# Return the extended docstring
|
||||
return lines
|
||||
|
||||
# Allow this module to be used as sphinx extension:
|
||||
def setup(app):
|
||||
# Generate docstrings for Django model fields
|
||||
# Register the docstring processor with sphinx
|
||||
app.connect('autodoc-process-docstring', improve_model_docstring)
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Allow :django:setting:`SITE_ID` to work.
|
||||
|
||||
def setup(app):
|
||||
app.add_crossref_type(
|
||||
directivename = "setting",
|
||||
rolename = "setting",
|
||||
indextemplate = "pair: %s; setting",
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
API Documentation
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
|
||||
polymorphic.admin
|
||||
polymorphic.contrib.extra_views
|
||||
polymorphic.contrib.guardian
|
||||
polymorphic.formsets
|
||||
polymorphic.managers
|
||||
polymorphic.models
|
||||
polymorphic.templatetags
|
||||
polymorphic.utils
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
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:
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
polymorphic.contrib.extra_views
|
||||
===============================
|
||||
|
||||
.. automodule:: polymorphic.contrib.extra_views
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
polymorphic.contrib.guardian
|
||||
============================
|
||||
|
||||
.. automodule:: polymorphic.contrib.guardian
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
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:
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
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:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
polymorphic.models
|
||||
==================
|
||||
|
||||
.. automodule:: polymorphic.models
|
||||
|
||||
.. autoclass:: polymorphic.models.PolymorphicModel
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
polymorphic.templatetags.polymorphic_admin_tags
|
||||
===============================================
|
||||
|
||||
.. automodule:: polymorphic.templatetags
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
polymorphic.utils
|
||||
=================
|
||||
|
||||
.. automodule:: polymorphic.utils
|
||||
:members:
|
||||
17
docs/conf.py
17
docs/conf.py
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
import sys
|
||||
import os
|
||||
import django
|
||||
import sphinx_rtd_theme
|
||||
|
||||
# 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
|
||||
|
|
@ -21,6 +23,9 @@ sys.path.insert(0, os.path.abspath('_ext'))
|
|||
sys.path.insert(0, os.path.abspath('..'))
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings'
|
||||
|
||||
if django.VERSION >= (1, 8):
|
||||
django.setup()
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
|
|
@ -31,7 +36,9 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings'
|
|||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.intersphinx'
|
||||
'sphinx.ext.intersphinx',
|
||||
'djangoext.docstrings',
|
||||
'djangoext.roles',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
|
@ -98,7 +105,8 @@ pygments_style = 'sphinx'
|
|||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# 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
|
||||
|
|
@ -252,5 +260,8 @@ texinfo_documents = [
|
|||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
#'http://docs.python.org/': None,
|
||||
'https://docs.djangoproject.com/en/dev': 'https://docs.djangoproject.com/en/dev/_objects',
|
||||
'https://docs.djangoproject.com/en/stable': 'https://docs.djangoproject.com/en/stable/_objects',
|
||||
}
|
||||
|
||||
# autodoc settings
|
||||
autodoc_member_order = 'groupwise'
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
Welcome to django-polymorphic's documentation!
|
||||
==============================================
|
||||
|
||||
Django-polymorphic simplifies using inherited models in Django projects.
|
||||
When a query is made at the base model, the inherited model classes are returned.
|
||||
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...
|
||||
|
||||
|
|
@ -43,6 +44,7 @@ Features
|
|||
* 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.
|
||||
|
||||
|
|
@ -56,6 +58,7 @@ Getting started
|
|||
quickstart
|
||||
admin
|
||||
performance
|
||||
third-party
|
||||
|
||||
Advanced topics
|
||||
---------------
|
||||
|
|
@ -67,9 +70,10 @@ Advanced topics
|
|||
migrating
|
||||
managers
|
||||
advanced
|
||||
third-party
|
||||
changelog
|
||||
contributing
|
||||
api/index
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
|
|||
|
|
@ -2,6 +2,35 @@ Third-party applications support
|
|||
================================
|
||||
|
||||
|
||||
django-guardian support
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 1.0.2
|
||||
|
||||
You can configure django-guardian_ to use the base model for object level permissions.
|
||||
Add this option to your settings:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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>`_.
|
||||
|
||||
|
||||
django-extra-views
|
||||
------------------
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
The :mod:`polymorphic.contrib.extra_views` package provides classes to display polymorphic formsets
|
||||
using the classes from 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`
|
||||
|
||||
|
||||
django-mptt support
|
||||
-------------------
|
||||
|
||||
|
|
@ -97,24 +126,9 @@ This doesn't work, since it needs to look for revisions of the child model. Usin
|
|||
the view of the actual child model is used, similar to the way the regular change and delete views are redirected.
|
||||
|
||||
|
||||
django-guardian support
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 1.0.2
|
||||
|
||||
You can configure django-guardian_ to use the base model for object level permissions.
|
||||
Add this option to your settings:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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>`_.
|
||||
|
||||
|
||||
.. _django-reversion: https://github.com/etianen/django-reversion
|
||||
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
|
||||
.. _django-extra-views: https://github.com/AndrewIngram/django-extra-views
|
||||
.. _django-guardian: https://github.com/django-guardian/django-guardian
|
||||
.. _django-mptt: https://github.com/django-mptt/django-mptt
|
||||
.. _django-polymorphic-tree: https://github.com/django-polymorphic/django-polymorphic-tree
|
||||
.. _django-guardian: https://github.com/django-guardian/django-guardian
|
||||
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
|
||||
.. _django-reversion: https://github.com/etianen/django-reversion
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInl
|
|||
"""
|
||||
Base class for variation of inlines based on generic foreign keys.
|
||||
"""
|
||||
#: The formset class
|
||||
formset = BaseGenericPolymorphicInlineFormSet
|
||||
|
||||
def get_formset(self, request, obj=None, **kwargs):
|
||||
|
|
@ -58,4 +59,5 @@ class GenericStackedPolymorphicInline(GenericPolymorphicInlineModelAdmin):
|
|||
"""
|
||||
The stacked layout for generic inlines.
|
||||
"""
|
||||
#: The default template to use.
|
||||
template = 'admin/polymorphic/edit_inline/stacked.html'
|
||||
|
|
|
|||
|
|
@ -245,4 +245,5 @@ class StackedPolymorphicInline(PolymorphicInlineModelAdmin):
|
|||
Stacked inline for django-polymorphic models.
|
||||
Since tabular doesn't make much sense with changed fields, just offer this one.
|
||||
"""
|
||||
#: The default template to use.
|
||||
template = 'admin/polymorphic/edit_inline/stacked.html'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
"""
|
||||
Polymorphic formsets support.
|
||||
|
||||
This allows creating formsets where each row can be a different form type.
|
||||
The logic of the formsets work similar to the standard Django formsets;
|
||||
there are factory methods to construct the classes with the proper form settings.
|
||||
|
|
@ -9,21 +7,6 @@ The "parent" formset hosts the entire model and their child model.
|
|||
For every child type, there is an :class:`PolymorphicFormSetChild` instance
|
||||
that describes how to display and construct the child.
|
||||
It's parameters are very similar to the parent's factory method.
|
||||
|
||||
See:
|
||||
* :func:`polymorphic_inlineformset_factory`
|
||||
* :class:`PolymorphicFormSetChild`
|
||||
|
||||
The internal machinery can be used to extend the formset classes. This includes:
|
||||
* :class:`BasePolymorphicModelFormSet`
|
||||
* :class:`BasePolymorphicInlineFormSet`
|
||||
* :func:`polymorphic_child_forms_factory`
|
||||
|
||||
For generic relations, a similar set is available:
|
||||
* :class:`BasePolymorphicGenericInlineFormSet`
|
||||
* :class:`PolymorphicGenericFormSetChild`
|
||||
* :func:`polymorphic_generic_inlineformset_factory`
|
||||
|
||||
"""
|
||||
from .models import (
|
||||
BasePolymorphicModelFormSet,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
""" PolymorphicManager
|
||||
Please see README.rst or DOCS.rst or http://chrisglass.github.com/django_polymorphic/
|
||||
"""
|
||||
The manager class for use in the models.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
import warnings
|
||||
|
|
@ -14,6 +14,12 @@ except ImportError:
|
|||
from django.utils.encoding import python_2_unicode_compatible # Django 1.5
|
||||
|
||||
|
||||
__all__ = (
|
||||
'PolymorphicManager',
|
||||
'PolymorphicQuerySet',
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class PolymorphicManager(models.Manager):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,17 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Seamless Polymorphic Inheritance for Django Models
|
||||
==================================================
|
||||
|
||||
Please see README.rst and DOCS.rst for further information.
|
||||
|
||||
Or on the Web:
|
||||
http://chrisglass.github.com/django_polymorphic/
|
||||
http://github.com/chrisglass/django_polymorphic
|
||||
|
||||
Copyright:
|
||||
This code and affiliated files are (C) by Bert Constantin and individual contributors.
|
||||
Please see LICENSE and AUTHORS for more information.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
|
@ -33,18 +22,8 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
Abstract base class that provides polymorphic behaviour
|
||||
for any model directly or indirectly derived from it.
|
||||
|
||||
For usage instructions & examples please see documentation.
|
||||
|
||||
PolymorphicModel declares one field for internal use (polymorphic_ctype)
|
||||
and provides a polymorphic manager as the default manager
|
||||
(and as 'objects').
|
||||
|
||||
PolymorphicModel overrides the save() and __init__ methods.
|
||||
|
||||
If your derived class overrides any of these methods as well, then you need
|
||||
to take care that you correctly call the method of the superclass, like:
|
||||
|
||||
super(YourClass,self).save(*args,**kwargs)
|
||||
PolymorphicModel declares one field for internal use (:attr:`polymorphic_ctype`)
|
||||
and provides a polymorphic manager as the default manager (and as 'objects').
|
||||
"""
|
||||
|
||||
# for PolymorphicModelBase, so it can tell which models are polymorphic and which are not (duck typing)
|
||||
|
|
@ -57,6 +36,7 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
abstract = True
|
||||
|
||||
# avoid ContentType related field accessor clash (an error emitted by model validation)
|
||||
#: The model field that stores the :class:`~django.contrib.contenttypes.models.ContentType` reference to the actual class.
|
||||
polymorphic_ctype = models.ForeignKey(ContentType, null=True, editable=False,
|
||||
related_name='polymorphic_%(app_label)s.%(class)s_set+')
|
||||
|
||||
|
|
@ -69,24 +49,24 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
base_objects = models.Manager()
|
||||
|
||||
@classmethod
|
||||
def translate_polymorphic_Q_object(self_class, q):
|
||||
return translate_polymorphic_Q_object(self_class, q)
|
||||
def translate_polymorphic_Q_object(cls, q):
|
||||
return translate_polymorphic_Q_object(cls, q)
|
||||
|
||||
def pre_save_polymorphic(self, using=DEFAULT_DB_ALIAS):
|
||||
"""Normally not needed.
|
||||
This function may be called manually in special use-cases. When the object
|
||||
is saved for the first time, we store its real class in polymorphic_ctype.
|
||||
When the object later is retrieved by PolymorphicQuerySet, it uses this
|
||||
field to figure out the real class of this object
|
||||
(used by PolymorphicQuerySet._get_real_instances)
|
||||
"""
|
||||
Make sure the ``polymorphic_ctype`` value is correctly set on this model.
|
||||
"""
|
||||
# This function may be called manually in special use-cases. When the object
|
||||
# is saved for the first time, we store its real class in polymorphic_ctype.
|
||||
# When the object later is retrieved by PolymorphicQuerySet, it uses this
|
||||
# field to figure out the real class of this object
|
||||
# (used by PolymorphicQuerySet._get_real_instances)
|
||||
if not self.polymorphic_ctype_id:
|
||||
self.polymorphic_ctype = ContentType.objects.db_manager(using).get_for_model(self, for_concrete_model=False)
|
||||
pre_save_polymorphic.alters_data = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""Overridden model save function which supports the polymorphism
|
||||
functionality (through pre_save_polymorphic)."""
|
||||
"""Calls :meth:`pre_save_polymorphic` and saves the model."""
|
||||
using = kwargs.get('using', self._state.db or DEFAULT_DB_ALIAS)
|
||||
self.pre_save_polymorphic(using=using)
|
||||
return super(PolymorphicModel, self).save(*args, **kwargs)
|
||||
|
|
@ -94,7 +74,8 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
|
||||
def get_real_instance_class(self):
|
||||
"""
|
||||
Normally not needed.
|
||||
Return the actual model type of the object.
|
||||
|
||||
If a non-polymorphic manager (like base_objects) has been used to
|
||||
retrieve objects, then the real class/type of these objects may be
|
||||
determined using this method.
|
||||
|
|
@ -121,10 +102,10 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
return model
|
||||
|
||||
def get_real_concrete_instance_class_id(self):
|
||||
model_class = self.get_real_instance_class()
|
||||
if model_class is None:
|
||||
ct = self.get_real_concrete_instance_class()
|
||||
if ct is None:
|
||||
return None
|
||||
return ContentType.objects.db_manager(self._state.db).get_for_model(model_class, for_concrete_model=True).pk
|
||||
return ct.pk
|
||||
|
||||
def get_real_concrete_instance_class(self):
|
||||
model_class = self.get_real_instance_class()
|
||||
|
|
@ -133,11 +114,18 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
|||
return ContentType.objects.db_manager(self._state.db).get_for_model(model_class, for_concrete_model=True).model_class()
|
||||
|
||||
def get_real_instance(self):
|
||||
"""Normally not needed.
|
||||
"""
|
||||
Upcast an object to it's actual type.
|
||||
|
||||
If a non-polymorphic manager (like base_objects) has been used to
|
||||
retrieve objects, then the complete object with it's real class/type
|
||||
and all fields may be retrieved with this method.
|
||||
Each method call executes one db query (if necessary)."""
|
||||
|
||||
.. note::
|
||||
Each method call executes one db query (if necessary).
|
||||
Use the :meth:`~polymorphic.managers.PolymorphicQuerySet.get_real_instances`
|
||||
to upcast a complete list in a single efficient query.
|
||||
"""
|
||||
real_model = self.get_real_instance_class()
|
||||
if real_model == self.__class__:
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class PolymorphicQuerySet(QuerySet):
|
|||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"init our queryset object member variables"
|
||||
# init our queryset object member variables
|
||||
self.polymorphic_disabled = False
|
||||
# A parallel structure to django.db.models.query.Query.deferred_loading,
|
||||
# which we maintain with the untranslated field names passed to
|
||||
|
|
@ -74,7 +74,7 @@ class PolymorphicQuerySet(QuerySet):
|
|||
super(PolymorphicQuerySet, self).__init__(*args, **kwargs)
|
||||
|
||||
def _clone(self, *args, **kwargs):
|
||||
"Django's _clone only copies its own variables, so we need to copy ours here"
|
||||
# Django's _clone only copies its own variables, so we need to copy ours here
|
||||
new = super(PolymorphicQuerySet, self)._clone(*args, **kwargs)
|
||||
new.polymorphic_disabled = self.polymorphic_disabled
|
||||
new.polymorphic_deferred_loading = (
|
||||
|
|
@ -101,17 +101,17 @@ class PolymorphicQuerySet(QuerySet):
|
|||
return qs
|
||||
|
||||
def instance_of(self, *args):
|
||||
"""Filter the queryset to only include the classes in args (and their subclasses).
|
||||
Implementation in _translate_polymorphic_filter_defnition."""
|
||||
"""Filter the queryset to only include the classes in args (and their subclasses)."""
|
||||
# Implementation in _translate_polymorphic_filter_defnition.
|
||||
return self.filter(instance_of=args)
|
||||
|
||||
def not_instance_of(self, *args):
|
||||
"""Filter the queryset to exclude the classes in args (and their subclasses).
|
||||
Implementation in _translate_polymorphic_filter_defnition."""
|
||||
"""Filter the queryset to exclude the classes in args (and their subclasses)."""
|
||||
# Implementation in _translate_polymorphic_filter_defnition."""
|
||||
return self.filter(not_instance_of=args)
|
||||
|
||||
def _filter_or_exclude(self, negate, *args, **kwargs):
|
||||
"We override this internal Django functon as it is used for all filter member functions."
|
||||
# We override this internal Django functon as it is used for all filter member functions.
|
||||
q_objects = translate_polymorphic_filter_definitions_in_args(self.model, args, using=self.db) # the Q objects
|
||||
additional_args = translate_polymorphic_filter_definitions_in_kwargs(self.model, kwargs, using=self.db) # filter_field='data'
|
||||
return super(PolymorphicQuerySet, self)._filter_or_exclude(negate, *(list(q_objects) + additional_args), **kwargs)
|
||||
|
|
@ -413,7 +413,7 @@ class PolymorphicQuerySet(QuerySet):
|
|||
By overriding it, we modify the objects that this queryset returns
|
||||
when it is evaluated (or its get method or other object-returning methods are called).
|
||||
|
||||
Here we do the same as:
|
||||
Here we do the same as::
|
||||
|
||||
base_result_objects = list(super(PolymorphicQuerySet, self).iterator())
|
||||
real_results = self._get_real_instances(base_result_objects)
|
||||
|
|
@ -464,6 +464,17 @@ class PolymorphicQuerySet(QuerySet):
|
|||
return '[ ' + ',\n '.join(result) + ' ]'
|
||||
|
||||
def get_real_instances(self, base_result_objects=None):
|
||||
"""
|
||||
Cast a list of objects to their actual classes.
|
||||
|
||||
This does roughly the same as::
|
||||
|
||||
return [ o.get_real_instance() for o in base_result_objects ]
|
||||
|
||||
but more efficiently.
|
||||
|
||||
:rtype: PolymorphicQuerySet
|
||||
"""
|
||||
"same as _get_real_instances, but make sure that __repr__ for ShowField... creates correct output"
|
||||
if not base_result_objects:
|
||||
base_result_objects = self
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
Template tags to use in the admin.
|
||||
|
||||
The ``{% breadcrumb_scope ... %}`` tag makes sure the ``{{ opts }}`` and ``{{ app_label }}``
|
||||
values are temporary based on the provided ``{{ base_opts }}``.
|
||||
This allows fixing the breadcrumb in admin templates:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% extends "admin/change_form.html" %}
|
||||
{% load polymorphic_admin_tags %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{% breadcrumb_scope base_opts %}{{ block.super }}{% endbreadcrumb_scope %}
|
||||
{% endblock %}
|
||||
"""
|
||||
Loading…
Reference in New Issue