Port documentation to Sphinx, cleanup README
This commit is contained in:
+153
@@ -0,0 +1,153 @@
|
||||
# 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."
|
||||
@@ -0,0 +1,85 @@
|
||||
Django admin integration
|
||||
========================
|
||||
|
||||
Off course, it's possible to register individual polymorphic models in the Django admin interface.
|
||||
However, to use these models in a single cohesive interface, some extra base classes are available.
|
||||
|
||||
The polymorphic admin interface works in a simple way:
|
||||
|
||||
* The add screen gains an additional step where the desired child model is selected.
|
||||
* The edit screen displays the admin interface of the child model.
|
||||
* The list screen still displays all objects of the base class.
|
||||
|
||||
The polymorphic admin is implemented via a parent admin that forwards the *edit* and *delete* views
|
||||
to the ``ModelAdmin`` of the derived child model. The *list* page is still implemented by the parent model admin.
|
||||
|
||||
Both the parent model and child model need to have a ``ModelAdmin`` class.
|
||||
Only the ``ModelAdmin`` class of the parent/base model has to be registered in the Django admin site.
|
||||
|
||||
The parent model
|
||||
----------------
|
||||
|
||||
The parent model needs to inherit ``PolymorphicParentModelAdmin``, and implement the following:
|
||||
|
||||
* ``base_model`` should be set
|
||||
* ``child_models`` or ``get_child_models()`` should return a list with (Model, ModelAdmin) tuple.
|
||||
|
||||
The exact implementation can depend on the way your module is structured.
|
||||
For simple inheritance situations, ``child_models`` is the best solution.
|
||||
For large applications, ``get_child_models()`` can be used to query a plugin registration system.
|
||||
|
||||
The child models
|
||||
----------------
|
||||
|
||||
The admin interface of the derived models should inherit from ``PolymorphicChildModelAdmin``.
|
||||
Again, ``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 ``base_form`` so the derived class will automatically include other fields in the form.
|
||||
* It allows to set ``base_fieldsets`` so the derived class will automatically display any extra fields.
|
||||
|
||||
The standard ``ModelAdmin`` attributes ``form`` and ``fieldsets`` should rather be avoided at the base class,
|
||||
because it will hide any additional fields which are defined in the derived model. Instead,
|
||||
use the ``base_form`` and ``base_fieldsets`` instead. The ``PolymorphicChildModelAdmin`` will
|
||||
automatically detect the additional fields that the child model has, display those in a separate fieldset.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.contrib import admin
|
||||
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin
|
||||
|
||||
|
||||
class ModelAChildAdmin(PolymorphicChildModelAdmin):
|
||||
""" Base admin class for all child models """
|
||||
base_model = ModelA
|
||||
|
||||
# By using these `base_...` attributes instead of the regular ModelAdmin `form` and `fieldsets`,
|
||||
# the additional fields of the child models are automatically added to the admin form.
|
||||
base_form = ...
|
||||
base_fieldsets = (
|
||||
...
|
||||
)
|
||||
|
||||
class ModelBAdmin(ModelAChildAdmin):
|
||||
# define custom features here
|
||||
|
||||
class ModelCAdmin(ModelBAdmin):
|
||||
# define custom features here
|
||||
|
||||
|
||||
class ModelAParentAdmin(PolymorphicParentModelAdmin):
|
||||
""" The parent model admin """
|
||||
base_model = ModelA
|
||||
child_models = (
|
||||
(ModelB, ModelBAdmin),
|
||||
(ModelC, ModelCAdmin),
|
||||
)
|
||||
|
||||
# Only the parent needs to be registered:
|
||||
admin.site.register(ModelA, ModelAParentAdmin)
|
||||
@@ -0,0 +1,272 @@
|
||||
Advanced features
|
||||
=================
|
||||
|
||||
In the examples below, these models are being used::
|
||||
|
||||
from polymorphic import PolymorphicModel
|
||||
|
||||
class ModelA(PolymorphicModel):
|
||||
field1 = models.CharField(max_length=10)
|
||||
|
||||
class ModelB(ModelA):
|
||||
field2 = models.CharField(max_length=10)
|
||||
|
||||
class ModelC(ModelB):
|
||||
field3 = models.CharField(max_length=10)
|
||||
|
||||
Filtering for classes (equivalent to python's isinstance() ):
|
||||
-------------------------------------------------------------
|
||||
|
||||
>>> ModelA.objects.instance_of(ModelB)
|
||||
.
|
||||
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
|
||||
In general, including or excluding parts of the inheritance tree::
|
||||
|
||||
ModelA.objects.instance_of(ModelB [, ModelC ...])
|
||||
ModelA.objects.not_instance_of(ModelB [, ModelC ...])
|
||||
|
||||
You can also use this feature in Q-objects (with the same result as above):
|
||||
|
||||
>>> ModelA.objects.filter( Q(instance_of=ModelB) )
|
||||
|
||||
|
||||
Polymorphic filtering (for fields in derived classes)
|
||||
-----------------------------------------------------
|
||||
|
||||
For example, cherrypicking objects from multiple derived classes
|
||||
anywhere in the inheritance tree, using Q objects (with the
|
||||
syntax: ``exact model name + three _ + field name``):
|
||||
|
||||
>>> ModelA.objects.filter( Q(ModelB___field2 = 'B2') | Q(ModelC___field3 = 'C3') )
|
||||
.
|
||||
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
|
||||
|
||||
Combining Querysets
|
||||
-------------------
|
||||
|
||||
Querysets could now be regarded as object containers that allow the
|
||||
aggregation of different object types, very similar to python
|
||||
lists - as long as the objects are accessed through the manager of
|
||||
a common base class:
|
||||
|
||||
>>> Base.objects.instance_of(ModelX) | Base.objects.instance_of(ModelY)
|
||||
.
|
||||
[ <ModelX: id 1, field_x (CharField)>,
|
||||
<ModelY: id 2, field_y (CharField)> ]
|
||||
|
||||
|
||||
ManyToManyField, ForeignKey, OneToOneField
|
||||
------------------------------------------
|
||||
|
||||
Relationship fields referring to polymorphic models work as
|
||||
expected: like polymorphic querysets they now always return the
|
||||
referred objects with the same type/class these were created and
|
||||
saved as.
|
||||
|
||||
E.g., if in your model you define::
|
||||
|
||||
field1 = OneToOneField(ModelA)
|
||||
|
||||
then field1 may now also refer to objects of type ``ModelB`` or ``ModelC``.
|
||||
|
||||
A ManyToManyField example::
|
||||
|
||||
# The model holding the relation may be any kind of model, polymorphic or not
|
||||
class RelatingModel(models.Model):
|
||||
many2many = models.ManyToManyField('ModelA') # ManyToMany relation to a polymorphic model
|
||||
|
||||
>>> o=RelatingModel.objects.create()
|
||||
>>> o.many2many.add(ModelA.objects.get(id=1))
|
||||
>>> o.many2many.add(ModelB.objects.get(id=2))
|
||||
>>> o.many2many.add(ModelC.objects.get(id=3))
|
||||
|
||||
>>> o.many2many.all()
|
||||
[ <ModelA: id 1, field1 (CharField)>,
|
||||
<ModelB: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
|
||||
|
||||
Using Third Party Models (without modifying them)
|
||||
-------------------------------------------------
|
||||
|
||||
Third party models can be used as polymorphic models without
|
||||
restrictions by subclassing them. E.g. using a third party
|
||||
model as the root of a polymorphic inheritance tree::
|
||||
|
||||
from thirdparty import ThirdPartyModel
|
||||
|
||||
class MyThirdPartyBaseModel(PolymorhpicModel, ThirdPartyModel):
|
||||
pass # or add fields
|
||||
|
||||
Or instead integrating the third party model anywhere into an
|
||||
existing polymorphic inheritance tree::
|
||||
|
||||
class MyBaseModel(SomePolymorphicModel):
|
||||
my_field = models.CharField(max_length=10)
|
||||
|
||||
class MyModelWithThirdParty(MyBaseModel, ThirdPartyModel):
|
||||
pass # or add fields
|
||||
|
||||
|
||||
Non-Polymorphic Queries
|
||||
-----------------------
|
||||
|
||||
If you insert ``.non_polymorphic()`` anywhere into the query chain, then
|
||||
django_polymorphic will simply leave out the final step of retrieving the
|
||||
real objects, and the manager/queryset will return objects of the type of
|
||||
the base class you used for the query, like vanilla Django would
|
||||
(``ModelA`` in this example).
|
||||
|
||||
>>> qs=ModelA.objects.non_polymorphic().all()
|
||||
>>> qs
|
||||
[ <ModelA: id 1, field1 (CharField)>,
|
||||
<ModelA: id 2, field1 (CharField)>,
|
||||
<ModelA: id 3, field1 (CharField)> ]
|
||||
|
||||
There are no other changes in the behaviour of the queryset. For example,
|
||||
enhancements for ``filter()`` or ``instance_of()`` etc. still work as expected.
|
||||
If you do the final step yourself, you get the usual polymorphic result:
|
||||
|
||||
>>> ModelA.objects.get_real_instances(qs)
|
||||
[ <ModelA: id 1, field1 (CharField)>,
|
||||
<ModelB: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
|
||||
|
||||
About Queryset Methods
|
||||
----------------------
|
||||
|
||||
* ``annotate()`` and ``aggregate()`` work just as usual, with the
|
||||
addition that the ``ModelX___field`` syntax can be used for the
|
||||
keyword arguments (but not for the non-keyword arguments).
|
||||
|
||||
* ``order_by()`` similarly supports the ``ModelX___field`` syntax
|
||||
for specifying ordering through a field in a submodel.
|
||||
|
||||
* ``distinct()`` works as expected. It only regards the fields of
|
||||
the base class, but this should never make a difference.
|
||||
|
||||
* ``select_related()`` works just as usual, but it can not (yet) be used
|
||||
to select relations in derived models
|
||||
(like ``ModelA.objects.select_related('ModelC___fieldxy')`` )
|
||||
|
||||
* ``extra()`` works as expected (it returns polymorphic results) but
|
||||
currently has one restriction: The resulting objects are required to have
|
||||
a unique primary key within the result set - otherwise an error is thrown
|
||||
(this case could be made to work, however it may be mostly unneeded)..
|
||||
The keyword-argument "polymorphic" is no longer supported.
|
||||
You can get back the old non-polymorphic behaviour
|
||||
by using ``ModelA.objects.non_polymorphic().extra(...)``.
|
||||
|
||||
* ``get_real_instances()`` allows you to turn a
|
||||
queryset or list of base model objects efficiently into the real objects.
|
||||
For example, you could do ``base_objects_queryset=ModelA.extra(...).non_polymorphic()``
|
||||
and then call ``real_objects=base_objects_queryset.get_real_instances()``. Or alternatively
|
||||
.``real_objects=ModelA.objects.get_real_instances(base_objects_queryset_or_object_list)``
|
||||
|
||||
* ``values()`` & ``values_list()`` currently do not return polymorphic
|
||||
results. This may change in the future however. If you want to use these
|
||||
methods now, it's best if you use ``Model.base_objects.values...`` as
|
||||
this is guaranteed to not change.
|
||||
|
||||
* ``defer()`` and ``only()`` are not yet supported (support will be added
|
||||
in the future).
|
||||
|
||||
|
||||
Using enhanced Q-objects in any Places
|
||||
--------------------------------------
|
||||
|
||||
The queryset enhancements (e.g. ``instance_of``) only work as arguments
|
||||
to the member functions of a polymorphic queryset. Occationally it may
|
||||
be useful to be able to use Q objects with these enhancements in other places.
|
||||
As Django doesn't understand these enhanced Q objects, you need to
|
||||
transform them manually into normal Q objects before you can feed them
|
||||
to a Django queryset or function::
|
||||
|
||||
normal_q_object = ModelA.translate_polymorphic_Q_object( Q(instance_of=Model2B) )
|
||||
|
||||
This function cannot be used at model creation time however (in models.py),
|
||||
as it may need to access the ContentTypes database table.
|
||||
|
||||
|
||||
Nicely Displaying Polymorphic Querysets
|
||||
---------------------------------------
|
||||
|
||||
In order to get the output as seen in all examples here, you need to use the
|
||||
:class:`~polymorphic.showfields.ShowFieldType` class mixin::
|
||||
|
||||
from polymorphic import PolymorphicModel, ShowFieldType
|
||||
|
||||
class ModelA(ShowFieldType, PolymorphicModel):
|
||||
field1 = models.CharField(max_length=10)
|
||||
|
||||
You may also use :class:`~polymorphic.showfields.ShowFieldContent`
|
||||
or :class:`~polymorphic.showfields.ShowFieldTypeAndContent` to display
|
||||
additional information when printing querysets (or converting them to text).
|
||||
|
||||
When showing field contents, they will be truncated to 20 characters. You can
|
||||
modify this behaviour by setting a class variable in your model like this::
|
||||
|
||||
class ModelA(ShowFieldType, PolymorphicModel):
|
||||
polymorphic_showfield_max_field_width = 20
|
||||
...
|
||||
|
||||
Similarly, pre-V1.0 output formatting can be re-estated by using
|
||||
``polymorphic_showfield_old_format = True``.
|
||||
|
||||
|
||||
|
||||
.. _restrictions:
|
||||
|
||||
Restrictions & Caveats
|
||||
----------------------
|
||||
|
||||
* Database Performance regarding concrete Model inheritance in general.
|
||||
Please see the :ref:`performance`.
|
||||
|
||||
* Queryset methods ``values()``, ``values_list()``, ``select_related()``,
|
||||
``defer()`` and ``only()`` are not yet fully supported (see above).
|
||||
``extra()`` has one restriction: the resulting objects are required to have
|
||||
a unique primary key within the result set.
|
||||
|
||||
* Diamond shaped inheritance: There seems to be a general problem
|
||||
with diamond shaped multiple model inheritance with Django models
|
||||
(tested with V1.1 - V1.3).
|
||||
An example is here: http://code.djangoproject.com/ticket/10808.
|
||||
This problem is aggravated when trying to enhance models.Model
|
||||
by subclassing it instead of modifying Django core (as we do here
|
||||
with PolymorphicModel).
|
||||
|
||||
* The enhanced filter-definitions/Q-objects only work as arguments
|
||||
for the methods of the polymorphic querysets. Please see above
|
||||
for ``translate_polymorphic_Q_object``.
|
||||
|
||||
* When using the ``dumpdata`` management command on polymorphic tables
|
||||
(or any table that has a reference to
|
||||
:class:`~django.contrib.contenttypes.models.ContentType`),
|
||||
include the ``--natural`` flag in the arguments.
|
||||
|
||||
|
||||
|
||||
.. old links:
|
||||
- http://code.djangoproject.com/wiki/ModelInheritance
|
||||
- http://lazypython.blogspot.com/2009/02/second-look-at-inheritance-and.html
|
||||
- http://www.djangosnippets.org/snippets/1031/
|
||||
- http://www.djangosnippets.org/snippets/1034/
|
||||
- http://groups.google.com/group/django-developers/browse_frm/thread/7d40ad373ebfa912/a20fabc661b7035d?lnk=gst&q=model+inheritance+CORBA#a20fabc661b7035d
|
||||
- http://groups.google.com/group/django-developers/browse_thread/thread/9bc2aaec0796f4e0/0b92971ffc0aa6f8?lnk=gst&q=inheritance#0b92971ffc0aa6f8
|
||||
- http://groups.google.com/group/django-developers/browse_thread/thread/3947c594100c4adb/d8c0af3dacad412d?lnk=gst&q=inheritance#d8c0af3dacad412d
|
||||
- http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/b76c9d8c89a5574f
|
||||
- http://peterbraden.co.uk/article/django-inheritance
|
||||
- http://www.hopelessgeek.com/2009/11/25/a-hack-for-multi-table-inheritance-in-django
|
||||
- http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982
|
||||
- http://stackoverflow.com/questions/1581024/django-inheritance-how-to-have-one-method-for-all-subclasses
|
||||
- http://groups.google.com/group/django-users/browse_thread/thread/cbdaf2273781ccab/e676a537d735d9ef?lnk=gst&q=polymorphic#e676a537d735d9ef
|
||||
- http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/bc18c18b2e83881e?lnk=gst&q=model+inheritance#bc18c18b2e83881e
|
||||
- http://code.djangoproject.com/ticket/10808
|
||||
- http://code.djangoproject.com/ticket/7270
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
Changelog
|
||||
==========
|
||||
|
||||
Version 0.4.2 (2013-04-10)
|
||||
--------------------------
|
||||
|
||||
* Used proper ``__version__`` marker.
|
||||
|
||||
|
||||
Version 0.4.1 (2013-04-10)
|
||||
--------------------------
|
||||
|
||||
* Add Django 1.5 and 1.6 support
|
||||
* Add proxy model support
|
||||
* Add default admin ``list_filter`` for polymorphic model type.
|
||||
* Fix queryset support of related objects.
|
||||
* Performed an overall cleanup of the project
|
||||
* **Deprecated** the ``queryset_class`` argument of the ``PolymorphicManager`` constructor, use the class attribute instead.
|
||||
* **Dropped** Django 1.1, 1.2 and 1.3 support
|
||||
|
||||
|
||||
Version 0.4 (2013-03-25)
|
||||
------------------------
|
||||
|
||||
* Update example project for Django 1.4
|
||||
* Added tox and Travis configuration
|
||||
|
||||
|
||||
Version 0.3.1 (2013-02-28)
|
||||
--------------------------
|
||||
|
||||
* SQL optimization, avoid query in pre_save_polymorphic()
|
||||
|
||||
|
||||
Version 0.3 (2013-02-28)
|
||||
------------------------
|
||||
|
||||
Many changes to the codebase happened, but no new version was released to pypi for years.
|
||||
0.3 contains fixes submitted by many contributors, huge thanks to everyone!
|
||||
|
||||
* Added a polymorphic admin interface.
|
||||
* PEP8 and code cleanups by various authors
|
||||
|
||||
|
||||
Version 0.2 (2012-11-12)
|
||||
------------------------
|
||||
|
||||
The 0.2 release serves as legacy release.
|
||||
It supports Django 1.1 up till 1.4 and Python 2.4 up till 2.7.
|
||||
|
||||
For a detailed list of it's changes, see the :doc:`archived changelog <changelog_archive>`.
|
||||
@@ -0,0 +1,325 @@
|
||||
Archive of old changelog entries
|
||||
================================
|
||||
|
||||
2011-01-24 V1.0 Release Candidate 1
|
||||
------------------------------------
|
||||
|
||||
* Fixed GitHub issue 15 (query result incomplete with inheritance).
|
||||
Thanks to John Debs for reporting and the test case.
|
||||
|
||||
|
||||
2011-12-20 Renaming, refactoring, new maintainer
|
||||
------------------------------------------------
|
||||
|
||||
Since the original author disappeared from the internet, we undertook to
|
||||
maintain and upgrade this piece of software.
|
||||
|
||||
The latest "legacy" tag should be V1.0-RC-1. Anything above that should be
|
||||
considered experimental and unstable until further notice (there be dragons).
|
||||
|
||||
New features, bug fixes and other improvements will be added to trunk from now on.
|
||||
|
||||
|
||||
2010-11-11 V1.0 Beta 2
|
||||
-----------------------
|
||||
|
||||
Beta 2 accumulated somewhat more changes than intended, and also
|
||||
has been delayed by DBMS benchmark testing I wanted to do on model
|
||||
inheritance. These benchmarks show that there are considerable
|
||||
problems with concrete model inheritance and contemporary DBM systems.
|
||||
The results will be forthcoming on the google discussion forum.
|
||||
|
||||
Please also see: http://www.jacobian.org/writing/concrete-inheritance/
|
||||
|
||||
The API should be stable now with Beta 2, so it's just about potential
|
||||
bugfixes from now on regarding V1.0.
|
||||
|
||||
Beta 2 is still intended for testing and development environments and not
|
||||
for production. No complaints have been heard regarding Beta 1 however,
|
||||
and Beta 1 is used on a few production sites by some enterprising users.
|
||||
|
||||
There will be a release candidate for V1.0 in the very near future.
|
||||
|
||||
New Features and changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* API CHANGE: ``.extra()`` has been re-implemented. Now it's polymorphic by
|
||||
default and works (nearly) without restrictions (please see docs). This is a (very)
|
||||
incompatible API change regarding previous versions of django_polymorphic.
|
||||
Support for the ``polymorphic`` keyword parameter has been removed.
|
||||
You can get back the non-polymorphic behaviour by using
|
||||
``ModelA.objects.non_polymorphic().extra(...)``.
|
||||
|
||||
* API CHANGE: ``ShowFieldContent`` and ``ShowFieldTypeAndContent`` now
|
||||
use a slightly different output format. If this causes too much trouble for
|
||||
your test cases, you can get the old behaviour back (mostly) by adding
|
||||
``polymorphic_showfield_old_format = True`` to your model definitions.
|
||||
``ShowField...`` now also produces more informative output for custom
|
||||
primary keys.
|
||||
|
||||
* ``.non_polymorphic()`` queryset member function added. This is preferable to
|
||||
using ``.base_objects...``, as it just makes the resulting queryset non-polymorphic
|
||||
and does not change anything else in the behaviour of the manager used (while
|
||||
``.base_objects`` is just a different manager).
|
||||
|
||||
* ``.get_real_instances()``: implementation modified to allow the following
|
||||
more simple and intuitive use::
|
||||
|
||||
>>> qs = ModelA.objects.all().non_polymorphic()
|
||||
>>> qs.get_real_instances()
|
||||
|
||||
which is equivalent to::
|
||||
|
||||
>>> ModelA.objects.all()
|
||||
|
||||
* added member function:
|
||||
``normal_q_object = ModelA.translate_polymorphic_Q_object(enhanced_q_object)``
|
||||
|
||||
* misc changes/improvements
|
||||
|
||||
Bugfixes
|
||||
~~~~~~~~
|
||||
|
||||
* Custom fields could cause problems when used as the primary key.
|
||||
In derived models, Django's automatic ".pk" field does not always work
|
||||
correctly for such custom fields: "some_object.pk" and "some_object.id"
|
||||
return different results (which they shouldn't, as pk should always be just
|
||||
an alias for the primary key field). It's unclear yet if the problem lies in
|
||||
Django or the affected custom fields. Regardless, the problem resulting
|
||||
from this has been fixed with a small workaround.
|
||||
"python manage.py test polymorphic" also tests and reports on this problem now.
|
||||
Thanks to Mathieu Steele for reporting and the test case.
|
||||
|
||||
2010-10-18 V1.0 Beta 1
|
||||
----------------------
|
||||
|
||||
This release is mostly a cleanup and maintenance release that also
|
||||
improves a number of minor things and fixes one (non-critical) bug.
|
||||
|
||||
Some pending API changes and corrections have been folded into this release
|
||||
in order to make the upcoming V1.0 API as stable as possible.
|
||||
|
||||
This release is also about getting feedback from you in case you don't
|
||||
approve of any of these changes or would like to get additional
|
||||
API fixes into V1.0.
|
||||
|
||||
The release contains a considerable amount of changes in some of the more
|
||||
critical parts of the software. It's intended for testing and development
|
||||
environments and not for production environments. For these, it's best to
|
||||
wait a few weeks for the proper V1.0 release, to allow some time for any
|
||||
potential problems to show up (if they exist).
|
||||
|
||||
If you encounter any such problems, please post them in the discussion group
|
||||
or open an issue on GitHub or BitBucket (or send me an email).
|
||||
|
||||
There also have been a number of minor API changes.
|
||||
Please see the README for more information.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* official Django 1.3 alpha compatibility
|
||||
|
||||
* ``PolymorphicModel.__getattribute__`` hack removed.
|
||||
This improves performance considerably as python's __getattribute__
|
||||
generally causes a pretty large processing overhead. It's gone now.
|
||||
|
||||
* the ``polymorphic_dumpdata`` management command is not needed anymore
|
||||
and has been disabled, as the regular Django dumpdata command now automatically
|
||||
works correctly with polymorphic models (for all supported versions of Django).
|
||||
|
||||
* ``.get_real_instances()`` has been elevated to an official part of the API::
|
||||
|
||||
real_objects = ModelA.objects.get_real_instances(base_objects_list_or_queryset)
|
||||
|
||||
allows you to turn a queryset or list of base objects into a list of the real instances.
|
||||
This is useful if e.g. you use ``ModelA.base_objects.extra(...)`` and then want to
|
||||
transform the result to its polymorphic equivalent.
|
||||
|
||||
* ``translate_polymorphic_Q_object`` (see DOCS)
|
||||
|
||||
* improved testing
|
||||
|
||||
* Changelog added: CHANGES.rst/html
|
||||
|
||||
Bugfixes
|
||||
~~~~~~~~
|
||||
|
||||
* Removed requirement for primary key to be an IntegerField.
|
||||
Thanks to Mathieu Steele and Malthe Borch.
|
||||
|
||||
API Changes
|
||||
~~~~~~~~~~~
|
||||
|
||||
**polymorphic_dumpdata**
|
||||
|
||||
The management command ``polymorphic_dumpdata`` is not needed anymore
|
||||
and has been disabled, as the regular Django dumpdata command now automatically
|
||||
works correctly with polymorphic models (for all supported versions of Django).
|
||||
|
||||
**Output of Queryset or Object Printing**
|
||||
|
||||
In order to improve compatibility with vanilla Django, printing quersets
|
||||
(__repr__ and __unicode__) does not use django_polymorphic's pretty printing
|
||||
by default anymore. To get the old behaviour when printing querysets,
|
||||
you need to replace your model definition:
|
||||
|
||||
>>> class Project(PolymorphicModel):
|
||||
|
||||
by:
|
||||
|
||||
>>> class Project(PolymorphicModel, ShowFieldType):
|
||||
|
||||
The mixin classes for pretty output have been renamed:
|
||||
|
||||
``ShowFieldTypes, ShowFields, ShowFieldsAndTypes``
|
||||
|
||||
are now:
|
||||
|
||||
``ShowFieldType, ShowFieldContent and ShowFieldTypeAndContent``
|
||||
|
||||
(the old ones still exist for compatibility)
|
||||
|
||||
**Running the Test suite with Django 1.3**
|
||||
|
||||
Django 1.3 requires ``python manage.py test polymorphic`` instead of
|
||||
just ``python manage.py test``.
|
||||
|
||||
|
||||
2010-2-22
|
||||
---------
|
||||
|
||||
IMPORTANT: API Changed (import path changed), and Installation Note
|
||||
|
||||
The django_polymorphic source code has been restructured
|
||||
and as a result needs to be installed like a normal Django App
|
||||
- either via copying the "polymorphic" directory into your
|
||||
Django project or by running setup.py. Adding 'polymorphic'
|
||||
to INSTALLED_APPS in settings.py is still optional, however.
|
||||
|
||||
The file `polymorphic.py` cannot be used as a standalone
|
||||
extension module anymore, as is has been split into a number
|
||||
of smaller files.
|
||||
|
||||
Importing works slightly different now: All relevant symbols are
|
||||
imported directly from 'polymorphic' instead from
|
||||
'polymorphic.models'::
|
||||
|
||||
# new way
|
||||
from polymorphic import PolymorphicModel, ...
|
||||
|
||||
# old way, doesn't work anymore
|
||||
from polymorphic.models import PolymorphicModel, ...
|
||||
|
||||
+ minor API addition: 'from polymorphic import VERSION, get_version'
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Python 2.4 compatibility, contributed by Charles Leifer. Thanks!
|
||||
|
||||
Bugfixes
|
||||
~~~~~~~~
|
||||
|
||||
Fix: The exception "...has no attribute 'sub_and_superclass_dict'"
|
||||
could be raised. (This occurred if a subclass defined __init__
|
||||
and accessed class members before calling the superclass __init__).
|
||||
Thanks to Mattias Brändström.
|
||||
|
||||
Fix: There could be name conflicts if
|
||||
field_name == model_name.lower() or similar.
|
||||
Now it is possible to give a field the same name as the class
|
||||
(like with normal Django models).
|
||||
(Found through the example provided by Mattias Brändström)
|
||||
|
||||
|
||||
2010-2-4
|
||||
--------
|
||||
|
||||
New features (and documentation)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
queryset order_by method added
|
||||
|
||||
queryset aggregate() and extra() methods implemented
|
||||
|
||||
queryset annotate() method implemented
|
||||
|
||||
queryset values(), values_list(), distinct() documented; defer(),
|
||||
only() allowed (but not yet supported)
|
||||
|
||||
setup.py added. Thanks to Andrew Ingram.
|
||||
|
||||
More about these additions in the docs:
|
||||
http://bserve.webhop.org/wiki/django_polymorphic/doc
|
||||
|
||||
Bugfixes
|
||||
~~~~~~~~
|
||||
|
||||
* fix remaining potential accessor name clashes (but this only works
|
||||
with Django 1.2+, for 1.1 no changes). Thanks to Andrew Ingram.
|
||||
|
||||
* fix use of 'id' model field, replaced with 'pk'.
|
||||
|
||||
* fix select_related bug for objects from derived classes (till now
|
||||
sel.-r. was just ignored)
|
||||
|
||||
"Restrictions & Caveats" updated
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Django 1.1 only - the names of polymorphic models must be unique
|
||||
in the whole project, even if they are in two different apps.
|
||||
This results from a restriction in the Django 1.1 "related_name"
|
||||
option (fixed in Django 1.2).
|
||||
|
||||
* Django 1.1 only - when ContentType is used in models, Django's
|
||||
seralisation or fixtures cannot be used. This issue seems to be
|
||||
resolved for Django 1.2 (changeset 11863: Fixed #7052, Added
|
||||
support for natural keys in serialization).
|
||||
|
||||
|
||||
2010-1-30
|
||||
---------
|
||||
|
||||
Fixed ContentType related field accessor clash (an error emitted
|
||||
by model validation) by adding related_name to the ContentType
|
||||
ForeignKey. This happened if your polymorphc model used a ContentType
|
||||
ForeignKey. Thanks to Andrew Ingram.
|
||||
|
||||
|
||||
2010-1-29
|
||||
---------
|
||||
|
||||
Restructured django_polymorphic into a regular Django add-on
|
||||
application. This is needed for the management commands, and
|
||||
also seems to be a generally good idea for future enhancements
|
||||
as well (and it makes sure the tests are always included).
|
||||
|
||||
The ``poly`` app - until now being used for test purposes only
|
||||
- has been renamed to ``polymorphic``. See DOCS.rst
|
||||
("installation/testing") for more info.
|
||||
|
||||
|
||||
2010-1-28
|
||||
---------
|
||||
|
||||
Added the polymorphic_dumpdata management command (github issue 4),
|
||||
for creating fixtures, this should be used instead of
|
||||
the normal Django dumpdata command.
|
||||
Thanks to Charles Leifer.
|
||||
|
||||
Important: Using ContentType together with dumpdata generally
|
||||
needs Django 1.2 (important as any polymorphic model uses
|
||||
ContentType).
|
||||
|
||||
2010-1-26
|
||||
---------
|
||||
|
||||
IMPORTANT - database schema change (more info in change log).
|
||||
I hope I got this change in early enough before anyone started
|
||||
to use polymorphic.py in earnest. Sorry for any inconvenience.
|
||||
This should be the final DB schema now.
|
||||
|
||||
Django's ContentType is now used instead of app-label and model-name
|
||||
This is a cleaner and more efficient solution
|
||||
Thanks to Ilya Semenov for the suggestion.
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# django-polymorphic documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun May 19 12:20:47 2013.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('_ext'))
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings'
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.intersphinx'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'django-polymorphic'
|
||||
copyright = u'2013, Bert Constantin, Chris Glass, Diederik van der Boor'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.4.2.dev0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.4.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'django-polymorphicdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'django-polymorphic.tex', u'django-polymorphic Documentation',
|
||||
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'django-polymorphic', u'django-polymorphic Documentation',
|
||||
[u'Bert Constantin, Chris Glass, Diederik van der Boor'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'django-polymorphic', u'django-polymorphic Documentation',
|
||||
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# 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',
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
You can contribute to *django-polymorphic* to forking the code on GitHub:
|
||||
|
||||
https://github.com/chrisglass/django_polymorphic
|
||||
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
We require features to be backed by a unit test.
|
||||
This way, we can test *django-polymorphic* against new Django versions.
|
||||
To run the included test suite, execute::
|
||||
|
||||
./runtests.py
|
||||
|
||||
To test support for multiple Python and Django versions, run tox from the repository root::
|
||||
|
||||
pip install tox
|
||||
tox
|
||||
|
||||
The Python versions need to be installed at your system.
|
||||
On Linux, download the versions at http://www.python.org/download/releases/.
|
||||
On MacOS X, use Homebrew_ to install other Python versions.
|
||||
|
||||
We currently support Python 2.6 and 2.7.
|
||||
Python 3.3 support is being worked on.
|
||||
|
||||
|
||||
Example project
|
||||
----------------
|
||||
|
||||
The repository (or tar file) contains a complete Django project
|
||||
that may be used for tests or experiments, without any installation needed.
|
||||
|
||||
The management command ``pcmd.py`` in the app ``pexp`` can be used for quick tests
|
||||
or experiments - modify this file (pexp/management/commands/pcmd.py) to your liking.
|
||||
|
||||
|
||||
Supported Django versions
|
||||
-------------------------
|
||||
|
||||
The current release should be usable with the supported releases of Django;
|
||||
the current stable release and the previous release. Supporting older Django
|
||||
versions is a nice-to-have feature, but not mandatory.
|
||||
|
||||
In case you need to use *django-polymorphic* with older Django versions,
|
||||
consider installing a previous version.
|
||||
|
||||
.. _Homebrew: http://mxcl.github.io/homebrew/
|
||||
@@ -0,0 +1,71 @@
|
||||
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.
|
||||
|
||||
When we store models that derive from a ``Project`` model...
|
||||
|
||||
>>> Project.objects.create(topic="Department Party")
|
||||
>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")
|
||||
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
||||
|
||||
...and want to retrieve all our projects, the subclassed models are returned!
|
||||
|
||||
>>> Project.objects.all()
|
||||
[ <Project: id 1, topic "Department Party">,
|
||||
<ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
|
||||
<ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]
|
||||
|
||||
Using vanilla Django, we get the base class objects, which is rarely what we wanted:
|
||||
|
||||
>>> Project.objects.all()
|
||||
[ <Project: id 1, topic "Department Party">,
|
||||
<Project: id 2, topic "Painting with Tim">,
|
||||
<Project: id 3, topic "Swallow Aerodynamics"> ]
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Full admin integation.
|
||||
* ORM integration:
|
||||
|
||||
* support for ForeignKey, ManyToManyField, OneToOneField descriptors.
|
||||
* support for proxy models
|
||||
* Filtering/ordering of derived models (``ArtProject___artist``).
|
||||
* Filtering model types: ``instance_of(...)`` and ``not_instance_of(...)``
|
||||
* Combining querysets of different models (``qs3 = qs1 | qs2``)
|
||||
* Support for custom user-defined managers.
|
||||
|
||||
* Uses the minumum amount of queries needed to fetch the derived models.
|
||||
* Disabling polymorphic behavior when needed.
|
||||
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
quickstart
|
||||
admin
|
||||
performance
|
||||
|
||||
Advanced topics
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
advanced
|
||||
managers
|
||||
changelog
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
@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
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
|
||||
Custom Managers, Querysets & Manager Inheritance
|
||||
================================================
|
||||
|
||||
Using a Custom Manager
|
||||
----------------------
|
||||
|
||||
A nice feature of Django is the possibility to define one's own custom object managers.
|
||||
This is fully supported with django_polymorphic: For creating a custom polymorphic
|
||||
manager class, just derive your manager from ``PolymorphicManager`` instead of
|
||||
``models.Manager``. As with vanilla Django, in your model class, you should
|
||||
explicitly add the default manager first, and then your custom manager::
|
||||
|
||||
from polymorphic import PolymorphicModel, PolymorphicManager
|
||||
|
||||
class TimeOrderedManager(PolymorphicManager):
|
||||
def get_query_set(self):
|
||||
qs = super(TimeOrderedManager,self).get_query_set()
|
||||
return qs.order_by('-start_date') # order the queryset
|
||||
|
||||
def most_recent(self):
|
||||
qs = self.get_query_set() # get my ordered queryset
|
||||
return qs[:10] # limit => get ten most recent entries
|
||||
|
||||
class Project(PolymorphicModel):
|
||||
objects = PolymorphicManager() # add the default polymorphic manager first
|
||||
objects_ordered = TimeOrderedManager() # then add your own manager
|
||||
start_date = DateTimeField() # project start is this date/time
|
||||
|
||||
The first manager defined ('objects' in the example) is used by
|
||||
Django as automatic manager for several purposes, including accessing
|
||||
related objects. It must not filter objects and it's safest to use
|
||||
the plain ``PolymorphicManager`` here.
|
||||
|
||||
Manager Inheritance
|
||||
-------------------
|
||||
|
||||
Polymorphic models inherit/propagate all managers from their
|
||||
base models, as long as these are polymorphic. This means that all
|
||||
managers defined in polymorphic base models continue to work as
|
||||
expected in models inheriting from this base model::
|
||||
|
||||
from polymorphic import PolymorphicModel, PolymorphicManager
|
||||
|
||||
class TimeOrderedManager(PolymorphicManager):
|
||||
def get_query_set(self):
|
||||
qs = super(TimeOrderedManager,self).get_query_set()
|
||||
return qs.order_by('-start_date') # order the queryset
|
||||
|
||||
def most_recent(self):
|
||||
qs = self.get_query_set() # get my ordered queryset
|
||||
return qs[:10] # limit => get ten most recent entries
|
||||
|
||||
class Project(PolymorphicModel):
|
||||
objects = PolymorphicManager() # add the default polymorphic manager first
|
||||
objects_ordered = TimeOrderedManager() # then add your own manager
|
||||
start_date = DateTimeField() # project start is this date/time
|
||||
|
||||
class ArtProject(Project): # inherit from Project, inheriting its fields and managers
|
||||
artist = models.CharField(max_length=30)
|
||||
|
||||
ArtProject inherited the managers ``objects`` and ``objects_ordered`` from Project.
|
||||
|
||||
``ArtProject.objects_ordered.all()`` will return all art projects ordered
|
||||
regarding their start time and ``ArtProject.objects_ordered.most_recent()``
|
||||
will return the ten most recent art projects.
|
||||
.
|
||||
|
||||
Using a Custom Queryset Class
|
||||
-----------------------------
|
||||
|
||||
The ``PolymorphicManager`` class accepts one initialization argument,
|
||||
which is the queryset class the manager should use. Just as with vanilla Django,
|
||||
you may define your own custom queryset classes. Just use PolymorphicQuerySet
|
||||
instead of Django's QuerySet as the base class::
|
||||
|
||||
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet
|
||||
|
||||
class MyQuerySet(PolymorphicQuerySet):
|
||||
def my_queryset_method(...):
|
||||
...
|
||||
|
||||
class MyModel(PolymorphicModel):
|
||||
my_objects=PolymorphicManager(MyQuerySet)
|
||||
...
|
||||
@@ -0,0 +1,40 @@
|
||||
.. _performance:
|
||||
|
||||
Performance Considerations
|
||||
==========================
|
||||
|
||||
Usually, when Django users create their own polymorphic ad-hoc solution
|
||||
without a tool like *django-polymorphic*, this usually results in a variation of ::
|
||||
|
||||
result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ]
|
||||
|
||||
which has very bad performance, as it introduces one additional
|
||||
SQL query for every object in the result which is not of class ``BaseModel``.
|
||||
Compared to these solutions, *django-polymorphic* has the advantage
|
||||
that it only needs 1 SQL query per *object type*, and not *per object*.
|
||||
|
||||
The current implementation is does not use any custom SQL or Django DB layer
|
||||
internals - it is purely based on the standard Django ORM. Specifically, the query::
|
||||
|
||||
result_objects = list( ModelA.objects.filter(...) )
|
||||
|
||||
performs one SQL query to retrieve ``ModelA`` objects and one additional
|
||||
query for each unique derived class occurring in result_objects.
|
||||
The best case for retrieving 100 objects is 1 SQL query if all are
|
||||
class ``ModelA``. If 50 objects are ``ModelA`` and 50 are ``ModelB``, then
|
||||
two queries are executed. The pathological worst case is 101 db queries if
|
||||
result_objects contains 100 different object types (with all of them
|
||||
subclasses of ``ModelA``).
|
||||
|
||||
Database notes
|
||||
--------------
|
||||
|
||||
Current relational DBM systems seem to have general problems with
|
||||
the SQL queries produced by object relational mappers like the Django
|
||||
ORM, if these use multi-table inheritance like Django's ORM does.
|
||||
The "inner joins" in these queries can perform very badly.
|
||||
This is independent of django_polymorphic and affects all uses of
|
||||
multi table Model inheritance.
|
||||
|
||||
Please also see this `post (and comments) from Jacob Kaplan-Moss
|
||||
<http://www.jacobian.org/writing/concrete-inheritance/>`_.
|
||||
@@ -0,0 +1,82 @@
|
||||
Quickstart
|
||||
===========
|
||||
|
||||
Install the project using::
|
||||
|
||||
pip install django-polymorphic
|
||||
|
||||
Update the settings file::
|
||||
|
||||
INSTALLED_APPS += (
|
||||
'polymorphic',
|
||||
'django.contrib.contenttypes',
|
||||
)
|
||||
|
||||
The current release of *django-polymorphic* supports Django 1.4, 1.5 and 1.6.
|
||||
|
||||
Making Your Models Polymorphic
|
||||
------------------------------
|
||||
|
||||
Use ``PolymorphicModel`` instead of Django's ``models.Model``, like so::
|
||||
|
||||
from polymorphic import PolymorphicModel
|
||||
|
||||
class Project(PolymorphicModel):
|
||||
topic = models.CharField(max_length=30)
|
||||
|
||||
class ArtProject(Project):
|
||||
artist = models.CharField(max_length=30)
|
||||
|
||||
class ResearchProject(Project):
|
||||
supervisor = models.CharField(max_length=30)
|
||||
|
||||
All models inheriting from your polymorphic models will be polymorphic as well.
|
||||
|
||||
Using Polymorphic Models
|
||||
------------------------
|
||||
|
||||
Create some objects:
|
||||
|
||||
>>> Project.objects.create(topic="Department Party")
|
||||
>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")
|
||||
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
||||
|
||||
Get polymorphic query results:
|
||||
|
||||
>>> Project.objects.all()
|
||||
[ <Project: id 1, topic "Department Party">,
|
||||
<ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
|
||||
<ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]
|
||||
|
||||
Use ``instance_of`` or ``not_instance_of`` for narrowing the result to specific subtypes:
|
||||
|
||||
>>> Project.objects.instance_of(ArtProject)
|
||||
[ <ArtProject: id 2, topic "Painting with Tim", artist "T. Turner"> ]
|
||||
|
||||
>>> Project.objects.instance_of(ArtProject) | Project.objects.instance_of(ResearchProject)
|
||||
[ <ArtProject: id 2, topic "Painting with Tim", artist "T. Turner">,
|
||||
<ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]
|
||||
|
||||
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"> ]
|
||||
|
||||
This is basically all you need to know, as *django-polymorphic* mostly
|
||||
works fully automatic and just delivers the expected results.
|
||||
|
||||
Note: When using the ``dumpdata`` management command on polymorphic tables
|
||||
(or any table that has a reference to :class:`~django.contrib.contenttypes.models.ContentType`),
|
||||
include the ``--natural`` flag in the arguments. This makes sure the
|
||||
:class:`~django.contrib.contenttypes.models.ContentType` models will be referenced by name
|
||||
instead of their primary key as that changes between Django instances.
|
||||
|
||||
|
||||
.. note::
|
||||
While *django-polymorphic* makes subclassed models easy to use in Django,
|
||||
we still encourage to use them with caution. Each subclassed model will require
|
||||
Django to perform an ``INNER JOIN`` to fetch the model fields from the database.
|
||||
While taking this in mind, there are valid reasons for using subclassed models.
|
||||
That's what this library is designed for!
|
||||
Reference in New Issue
Block a user