Add API documentation to the package!
This commit is contained in:
@@ -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):
|
||||
"""
|
||||
|
||||
+27
-39
@@ -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
@@ -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
|
||||
|
||||
@@ -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 %}
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user