Add API documentation to the package!

This commit is contained in:
Diederik van der Boor
2017-01-09 16:53:12 +01:00
parent c76cc663e0
commit f9fffc44c1
25 changed files with 397 additions and 93 deletions
+2
View File
@@ -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'
+1
View File
@@ -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'
-17
View File
@@ -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,
+8 -2
View File
@@ -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):
"""
+27 -39
View File
@@ -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
+21 -10
View File
@@ -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,10 +413,10 @@ 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)
base_result_objects = list(super(PolymorphicQuerySet, self).iterator())
real_results = self._get_real_instances(base_result_objects)
for o in real_results: yield o
but it requests the objects in chunks from the database,
@@ -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
+16
View File
@@ -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 %}
"""