[Python-modules-commits] [python-django-adminsortable] 01/02: Imported Upstream version 2.0.10

Joost van Baal joostvb at moszumanska.debian.org
Tue Mar 1 08:39:06 UTC 2016


This is an automated email from the git hooks/post-receive script.

joostvb pushed a commit to branch master
in repository python-django-adminsortable.

commit 1b06a38423274f8747dfb9fa04f2fe694a1497fd
Author: Joost van Baal-Ilić <joostvb at nusku.mdcc.cx>
Date:   Tue Mar 1 09:38:30 2016 +0100

    Imported Upstream version 2.0.10
---
 MANIFEST.in                                        |   4 +
 PKG-INFO                                           |  19 +
 README.rst                                         | 629 +++++++++++++++++++++
 adminsortable/__init__.py                          |  17 +
 adminsortable/admin.py                             | 371 ++++++++++++
 adminsortable/fields.py                            |  20 +
 adminsortable/locale/de/LC_MESSAGES/django.mo      | Bin 0 -> 1597 bytes
 adminsortable/locale/de/LC_MESSAGES/django.po      | 105 ++++
 adminsortable/locale/en/LC_MESSAGES/django.po      |  46 ++
 adminsortable/locale/es/LC_MESSAGES/django.mo      | Bin 0 -> 1814 bytes
 adminsortable/locale/es/LC_MESSAGES/django.po      | 106 ++++
 adminsortable/locale/nl/LC_MESSAGES/django.mo      | Bin 0 -> 1009 bytes
 adminsortable/locale/nl/LC_MESSAGES/django.po      |  49 ++
 adminsortable/locale/pl/LC_MESSAGES/django.mo      | Bin 0 -> 1864 bytes
 adminsortable/locale/pl/LC_MESSAGES/django.po      | 109 ++++
 adminsortable/locale/pt_BR/LC_MESSAGES/django.mo   | Bin 0 -> 1511 bytes
 adminsortable/locale/pt_BR/LC_MESSAGES/django.po   |  98 ++++
 adminsortable/locale/ru/LC_MESSAGES/django.mo      | Bin 0 -> 2199 bytes
 adminsortable/locale/ru/LC_MESSAGES/django.po      | 107 ++++
 adminsortable/models.py                            | 141 +++++
 .../static/adminsortable/css/admin.sortable.css    |  57 ++
 .../adminsortable/css/admin.sortable.inline.css    |  25 +
 .../static/adminsortable/js/admin.sortable.js      |  50 ++
 .../js/admin.sortable.stacked.inlines.js           |  70 +++
 .../js/admin.sortable.tabular.inlines.js           |  69 +++
 .../adminsortable/js/jquery-ui-django-admin.min.js |   8 +
 .../static/adminsortable/js/jquery.django-csrf.js  |  32 ++
 .../templates/adminsortable/change_form.html       |  33 ++
 .../templates/adminsortable/change_list.html       |  72 +++
 .../adminsortable/change_list_with_sort_link.html  |  15 +
 .../adminsortable/edit_inline/stacked-1.5.x.html   |  86 +++
 .../adminsortable/edit_inline/stacked.html         |  35 ++
 .../adminsortable/edit_inline/tabular-1.5.x.html   | 134 +++++
 .../adminsortable/edit_inline/tabular.html         |  91 +++
 .../templates/adminsortable/shared/fieldset.html   |  35 ++
 .../templates/adminsortable/shared/list_items.html |  12 +
 .../adminsortable/shared/nested_objects.html       |  26 +
 .../templates/adminsortable/shared/object_rep.html |   6 +
 .../templates/adminsortable/shared/objects.html    |   7 +
 adminsortable/templatetags/__init__.py             |   0
 adminsortable/templatetags/adminsortable_tags.py   |  35 ++
 .../templatetags/django_template_additions.py      |  86 +++
 adminsortable/utils.py                             |  35 ++
 django_admin_sortable.egg-info/PKG-INFO            |  19 +
 django_admin_sortable.egg-info/SOURCES.txt         |  51 ++
 .../dependency_links.txt                           |   1 +
 django_admin_sortable.egg-info/not-zip-safe        |   1 +
 django_admin_sortable.egg-info/pbr.json            |   1 +
 django_admin_sortable.egg-info/requires.txt        |   1 +
 django_admin_sortable.egg-info/top_level.txt       |   1 +
 setup.cfg                                          |   5 +
 setup.py                                           |  30 +
 52 files changed, 2950 insertions(+)

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..117a1b9
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,4 @@
+recursive-include adminsortable/static *
+recursive-include adminsortable/templates *
+recursive-include adminsortable/locale *
+prune sample_project
\ No newline at end of file
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..84cebe5
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,19 @@
+Metadata-Version: 1.1
+Name: django-admin-sortable
+Version: 2.0.10
+Summary: Drag and drop sorting for models and inline models in Django admin.
+Home-page: https://github.com/iambrandontaylor/django-admin-sortable
+Author: Brandon Taylor
+Author-email: alsoicode at gmail.com
+License: APL
+Description: UNKNOWN
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Utilities
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..9aa2fd1
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,629 @@
+Django Admin Sortable
+=====================
+
+|Build Status|
+
+Current version: 2.0.10
+
+This project makes it easy to add drag-and-drop ordering to any model in
+Django admin. Inlines for a sortable model may also be made sortable,
+enabling individual items or groups of items to be sortable.
+
+Sorting model instances with a sortable parent:
+
+.. figure:: http://res.cloudinary.com/alsoicode/image/upload/v1451237555/django-admin-sortable/sortable-models.jpg
+   :alt: sortable-models
+
+   sortable-models
+
+Sorting inlines:
+
+.. figure:: http://res.cloudinary.com/alsoicode/image/upload/v1451237555/django-admin-sortable/sortable-inlines.jpg
+   :alt: sortable-inlines
+
+   sortable-inlines
+
+Supported Django Versions
+-------------------------
+
+If you're using Django 1.4.x, use django-admin-sortable 1.4.9 or below.
+For Django 1.5.x or higher, use the latest version of
+django-admin-sortable.
+
+django-admin-sortable 1.5.2 introduced backward-incompatible changes for
+Django 1.4.x
+
+django-admin-sortable 1.6.6 introduced a backward-incompatible change
+for the ``sorting_filters`` attribute. Please convert your attributes to
+the new tuple-based format.
+
+django-admin-sortable 1.7.1 and higher are compatible with Python 3.
+
+Installation
+------------
+
+1. ``$ pip install django-admin-sortable``
+
+--or--
+
+Download django-admin-sortable from
+`source <https://github.com/iambrandontaylor/django-admin-sortable/archive/master.zip>`__
+
+1. Unzip the directory and cd into the uncompressed project directory
+2. 
+
+   -  Optional: Enable your virtualenv
+
+3. Run ``$ python setup.py install`` or add ``adminsortable`` to your
+   PYTHONPATH.
+
+Configuration
+-------------
+
+1. Add ``adminsortable`` to your ``INSTALLED_APPS``.
+2. Ensure ``django.core.context_processors.static`` is in your
+   ``TEMPLATE_CONTEXT_PROCESSORS``.
+
+Static Media
+~~~~~~~~~~~~
+
+Preferred: Use the `staticfiles
+app <https://docs.djangoproject.com/en/1.6/ref/contrib/staticfiles/>`__
+
+Alternate: Copy the ``adminsortable`` folder from the ``static`` folder
+to the location you serve static files from.
+
+Testing
+~~~~~~~
+
+Have a look at the included sample\_project to see working examples. The
+login credentials for admin are: admin/admin
+
+When a model is sortable, a tool-area link will be added that says
+"Change Order". Click this link, and you will be taken to the custom
+view where you can drag-and-drop the records into order.
+
+Inlines may be drag-and-dropped into any order directly from the change
+form.
+
+Usage
+-----
+
+Models
+~~~~~~
+
+To add "sortability" to a model, you need to inherit ``SortableMixin``
+and at minimum, define:
+
+-  The field which should be used for ``Meta.ordering``, which must
+   resolve to one of the integer fields defined in Django's ORM:
+-  ``PositiveIntegerField``
+-  ``IntegerField``
+-  ``PositiveSmallIntegerField``
+-  ``SmallIntegerField``
+-  ``BigIntegerField``
+
+-  ``Meta.ordering`` **must only contain one value**, otherwise, your
+   objects will not be sorted correctly.
+-  It is recommended that you set ``editable=False`` and
+   ``db_index=True`` on the field defined in ``Meta.ordering`` for a
+   seamless Django admin experience and faster lookups on the objects.
+
+Sample Model:
+
+::
+
+    # models.py
+    from adminsortable.models import SortableMixin
+
+    class MySortableClass(SortableMixin):
+        class Meta:
+            verbose_name = 'My Sortable Class'
+            verbose_name_plural = 'My Sortable Classes'
+            ordering = ['the_order']
+
+        title = models.CharField(max_length=50)
+
+        # define the field the model should be ordered by
+        the_order = models.PositiveIntegerField(default=0, editable=False, db_index=True)
+
+        def __unicode__(self):
+            return self.title
+
+Common Use Case
+^^^^^^^^^^^^^^^
+
+A common use case is to have child objects that are sortable relative to
+a parent. If your parent object is also sortable, here's how you would
+set up your models and admin options:
+
+::
+
+    # models.py
+    from adminsortable.fields import SortableForeignKey
+
+    class Category(SortableMixin):
+        class Meta:
+            ordering = ['category_order']
+            verbose_name_plural = 'Categories'
+
+        title = models.CharField(max_length=50)
+
+        # ordering field
+        category_order = models.PositiveIntegerField(default=0, editable=False, db_index=True)
+
+    class Project(SortableMixin):
+        class Meta:
+            ordering = ['project_order']
+
+        category = SortableForeignKey(Category)
+        title = models.CharField(max_length=50)
+
+        # ordering field
+        project_order = models.PositiveIntegerField(default=0, editable=False, db_index=True)
+
+        def __unicode__(self):
+            return self.title
+
+    # admin.py
+    from adminsortable.admin import SortableAdmin
+
+    from your_app.models import Category, Project
+
+    admin.site.register(Category, SortableAdmin)
+    admin.site.register(Project, SortableAdmin)
+
+Sometimes you might have a parent model that is not sortable, but has
+child models that are. In that case define your models and admin options
+as such:
+
+::
+
+    from adminsortable.fields import SortableForeignKey
+
+    # models.py
+    class Category(models.Model):
+        class Meta:
+            verbose_name_plural = 'Categories'
+
+        title = models.CharField(max_length=50)
+        ...
+
+    class Project(SortableMixin):
+        class Meta:
+            ordering = ['project_order']
+
+        category = SortableForeignKey(Category)
+        title = models.CharField(max_length=50)
+
+        # ordering field
+        project_order = models.PositiveIntegerField(default=0, editable=False, db_index=True)
+
+        def __unicode__(self):
+            return self.title
+
+    # admin
+    from adminsortable.admin import NonSortableParentAdmin, SortableStackedInline
+
+    from your_app.models import Category, Project
+
+    class ProjectInline(SortableStackedInline):
+        model = Project
+        extra = 1
+
+    class CategoryAdmin(NonSortableParentAdmin):
+        inlines = [ProjectInline]
+
+    admin.site.register(Category, CategoryAdmin)
+
+The ``NonSortableParentAdmin`` class is necessary to wire up the
+additional URL patterns and JavaScript that Django Admin Sortable needs
+to make your models sortable. The child model does not have to be an
+inline model, it can be wired directly to Django admin and the objects
+will be grouped by the non-sortable foreign key when sorting.
+
+Backwards Compatibility
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If you previously used Django Admin Sortable, **DON'T PANIC** -
+everything will still work exactly as before ***without any changes to
+your code***. Going forward, it is recommended that you use the new
+``SortableMixin`` on your models, as pre-2.0 compatibility might not be
+a permanent thing.
+
+Please note however that the ``Sortable`` class still contains the
+hard-coded ``order`` field, and meta inheritance requirements:
+
+::
+
+    # legacy model definition
+
+    from adminsortable.models import Sortable
+
+    class Project(Sortable):
+        class Meta(Sortable.Meta):
+            pass
+        title = models.CharField(max_length=50)
+
+        def __unicode__(self):
+            return self.title
+
+Model Instance Methods
+^^^^^^^^^^^^^^^^^^^^^^
+
+Each instance of a sortable model has two convenience methods to get the
+next or previous instance:
+
+::
+
+    .get_next()
+    .get_previous()
+
+By default, these methods will respect their order in relation to a
+``SortableForeignKey`` field, if present. Meaning, that given the
+following data:
+
+::
+
+    | Parent Model 1 |               |
+    |                | Child Model 1 |
+    |                | Child Model 2 |
+    | Parent Model 2 |               |
+    |                | Child Model 3 |
+    |                | Child Model 4 |
+    |                | Child Model 5 |
+
+"Child Model 2" ``get_next()`` would return ``None`` "Child Model 3"
+``get_previous`` would return ``None``
+
+If you wish to override this behavior, pass in:
+``filter_on_sortable_fk=False``:
+
+::
+
+    your_instance.get_next(filter_on_sortable_fk=False)
+
+You may also pass in additional ORM "extra\_filters" as a dictionary,
+should you need to:
+
+::
+
+    your_instance.get_next(extra_filters={'title__icontains': 'blue'})
+
+Adding Sorting to an existing model
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django 1.6.x or below
+^^^^^^^^^^^^^^^^^^^^^
+
+If you're adding Sorting to an existing model, it is recommended that
+you use `django-south <http://south.areacode.com/>`__ to create a schema
+migration to add the "order" field to your model. You will also need to
+create a data migration in order to add the appropriate values for the
+"order" column.
+
+Example assuming a model named "Category":
+
+::
+
+    def forwards(self, orm):
+        for index, category in enumerate(orm.Category.objects.all()):
+            category.order = index + 1
+            category.save()
+
+See: `this
+link <http://south.readthedocs.org/en/latest/tutorial/part3.html>`__ for
+more information on South Data Migrations.
+
+Django 1.7.x or higher
+^^^^^^^^^^^^^^^^^^^^^^
+
+Since schema migrations are built into Django 1.7, you don't have to use
+south, but the process of adding and running migrations is nearly
+identical. Take a look at the
+`Migrations <https://docs.djangoproject.com/en/1.7/topics/migrations/>`__
+documentation to get started.
+
+Django Admin Integration
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+To enable sorting in the admin, you need to inherit from
+``SortableAdmin``:
+
+::
+
+    from django.contrib import admin
+    from myapp.models import MySortableClass
+    from adminsortable.admin import SortableAdmin
+
+    class MySortableAdminClass(SortableAdmin):
+        """Any admin options you need go here"""
+
+    admin.site.register(MySortableClass, MySortableAdminClass)
+
+To enable sorting on TabularInline models, you need to inherit from
+SortableTabularInline:
+
+::
+
+    from adminsortable.admin import SortableTabularInline
+
+    class MySortableTabularInline(SortableTabularInline):
+       """Your inline options go here"""
+
+To enable sorting on StackedInline models, you need to inherit from
+SortableStackedInline:
+
+::
+
+    from adminsortable.admin import SortableStackedInline
+
+    class MySortableStackedInline(SortableStackedInline):
+       """Your inline options go here"""
+
+There are also generic equivalents that you can inherit from:
+
+::
+
+    from adminsortable.admin import (SortableGenericTabularInline,
+        SortableGenericStackedInline)
+        """Your generic inline options go here"""
+
+If your parent model is *not* sortable, but has child inlines that are,
+your parent model needs to inherit from ``NonSortableParentAdmin``:
+
+::
+
+    from adminsortable.admin import (NonSortableParentAdmin,
+        SortableTabularInline)
+
+    class ChildTabularInline(SortableTabularInline):
+        model = YourModel
+
+    class ParentAdmin(NonSortableParentAdmin):
+        inlines = [ChildTabularInline]
+
+Overriding ``queryset()``
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+django-admin-sortable supports custom queryset overrides on admin models
+and inline models in Django admin!
+
+If you're providing an override of a SortableAdmin or Sortable inline
+model, you don't need to do anything extra. django-admin-sortable will
+automatically honor your queryset.
+
+Have a look at the WidgetAdmin class in the sample project for an
+example of an admin class with a custom ``queryset()`` override.
+
+Overriding ``queryset()`` for an inline model
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is a special case, which requires a few lines of extra code to
+properly determine the sortability of your model. Example:
+
+::
+
+    # add this import to your admin.py
+    from adminsortable.utils import get_is_sortable
+
+
+    class ComponentInline(SortableStackedInline):
+        model = Component
+
+        def queryset(self, request):
+            qs = super(ComponentInline, self).queryset(request).filter(
+                title__icontains='foo')
+
+            # You'll need to add these lines to determine if your model
+            # is sortable once we hit the change_form() for the parent model.
+
+            if get_is_sortable(qs):
+                self.model.is_sortable = True
+            else:
+                self.model.is_sortable = False
+            return qs
+
+If you override the queryset of an inline, the number of objects present
+may change, and adminsortable won't be able to automatically determine
+if the inline model is sortable from here, which is why we have to set
+the ``is_sortable`` property of the model in this method.
+
+Sorting subsets of objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is also possible to sort a subset of objects in your model by adding
+a ``sorting_filters`` tuple. This works exactly the same as
+``.filter()`` on a QuerySet, and is applied *after* ``get_queryset()``
+on the admin class, allowing you to override the queryset as you would
+normally in admin but apply additional filters for sorting. The text
+"Change Order of" will appear before each filter in the Change List
+template, and the filter groups are displayed from left to right in the
+order listed. If no ``sorting_filters`` are specified, the text "Change
+Order" will be displayed for the link.
+
+Self-Referential SortableForeignKey
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can specify a self-referential SortableForeignKey field, however the
+admin interface will currently show a model that is a grandchild at the
+same level as a child. I'm working to resolve this issue.
+
+Important!
+''''''''''
+
+django-admin-sortable 1.6.6 introduced a backwards-incompatible change
+for ``sorting_filters``. Previously this attribute was defined as a
+dictionary, so you'll need to change your values over to the new
+tuple-based format.
+
+An example of sorting subsets would be a "Board of Directors". In this
+use case, you have a list of "People" objects. Some of these people are
+on the Board of Directors and some not, and you need to sort them
+independently.
+
+::
+
+    class Person(Sortable):
+        class Meta(Sortable.Meta):
+            verbose_name_plural = 'People'
+
+        first_name = models.CharField(max_length=50)
+        last_name = models.CharField(max_length=50)
+        is_board_member = models.BooleanField('Board Member', default=False)
+
+        sorting_filters = (
+            ('Board Members', {'is_board_member': True}),
+            ('Non-Board Members', {'is_board_member': False}),
+        )
+
+        def __unicode__(self):
+            return '{} {}'.format(self.first_name, self.last_name)
+
+Extending custom templates
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+By default, adminsortable's change form and change list views inherit
+from Django admin's standard templates. Sometimes you need to have a
+custom change form or change list, but also need adminsortable's CSS and
+JavaScript for inline models that are sortable for example.
+
+SortableAdmin has two attributes you can override for this use case:
+
+::
+
+    change_form_template_extends
+    change_list_template_extends
+
+These attributes have default values of:
+
+::
+
+    change_form_template_extends = 'admin/change_form.html'
+    change_list_template_extends = 'admin/change_list.html'
+
+If you need to extend the inline change form templates, you'll need to
+select the right one, depending on your version of Django. For Django
+1.5.x or below, you'll need to extend one of the following:
+
+::
+
+    templates/adminsortable/edit_inline/stacked-1.5.x.html
+    templates/adminsortable/edit_inline/tabular-inline-1.5.x.html
+
+For Django 1.6.x, extend:
+
+::
+
+    templates/adminsortable/edit_inline/stacked.html
+    templates/adminsortable/edit_inline/tabular.html
+
+A Special Note About Stacked Inlines...
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The height of a stacked inline model can dynamically increase, which can
+make them difficult to sort. If you anticipate the height of a stacked
+inline is going to be very tall, I would suggest using
+SortableTabularInline instead.
+
+Django-CMS integration
+~~~~~~~~~~~~~~~~~~~~~~
+
+Django-CMS plugins use their own change form, and thus won't
+automatically include the necessary JavaScript for django-admin-sortable
+to work. Fortunately, this is easy to resolve, as the ``CMSPlugin``
+class allows a change form template to be specified:
+
+::
+
+    # example plugin
+    from cms.plugin_base import CMSPluginBase
+
+    class CMSCarouselPlugin(CMSPluginBase):
+        admin_preview = False
+        change_form_template = 'cms/sortable-stacked-inline-change-form.html'
+        inlines = [SlideInline]
+        model = Carousel
+        name = _('Carousel')
+        render_template = 'carousels/carousel.html'
+
+        def render(self, context, instance, placeholder):
+            context.update({
+                'carousel': instance,
+                'placeholder': placeholder
+            })
+            return context
+
+    plugin_pool.register_plugin(CMSCarouselPlugin)
+
+The contents of ``sortable-stacked-inline-change-form.html`` at a
+minimum need to extend the extrahead block with:
+
+::
+
+    {% extends "admin/cms/page/plugin_change_form.html" %}
+    {% load static from staticfiles %}
+
+    {% block extrahead %}
+        {{ block.super }}
+        <script type="text/javascript" src="{% static 'adminsortable/js/jquery-ui-django-admin.min.js' %}"></script>
+        <script type="text/javascript" src="{% static 'adminsortable/js/jquery.django-csrf.js' %}"></script>
+        <script type="text/javascript" src="{% static 'adminsortable/js/admin.sortable.stacked.inlines.js' %}"></script>
+
+        <link rel="stylesheet" type="text/css" href="{% static 'adminsortable/css/admin.sortable.inline.css' %}" />
+    {% endblock extrahead %}
+
+Sorting within Django-CMS is really only feasible for inline models of a
+plugin as Django-CMS already includes sorting for plugin instances. For
+tabular inlines, just substitute:
+
+::
+
+    <script src="{% static 'adminsortable/js/admin.sortable.stacked.inlines.js' %}"></script>
+
+with:
+
+::
+
+    <script src="{% static 'adminsortable/js/admin.sortable.tabular.inlines.js' %}"></script>
+
+Rationale
+~~~~~~~~~
+
+Other projects have added drag-and-drop ordering to the ChangeList view,
+however this introduces a couple of problems...
+
+-  The ChangeList view supports pagination, which makes drag-and-drop
+   ordering across pages impossible.
+-  The ChangeList view by default, does not order records based on a
+   foreign key, nor distinguish between rows that are associated with a
+   foreign key. This makes ordering the records grouped by a foreign key
+   impossible.
+-  The ChangeList supports in-line editing, and adding drag-and-drop
+   ordering on top of that just seemed a little much in my opinion.
+
+Status
+~~~~~~
+
+django-admin-sortable is currently used in production.
+
+What's new in 2.0.10?
+~~~~~~~~~~~~~~~~~~~~~
+
+-  Bugfix for accessing custom ``order`` property of model. Thanks
+   [@theithec](https://github.com/theithec) for reporting the issue.
+
+Future
+~~~~~~
+
+-  Better template support for foreign keys that are self referential.
+   If someone would like to take on rendering recursive sortables, that
+   would be super.
+
+License
+~~~~~~~
+
+django-admin-sortable is released under the Apache Public License v2.
+
+.. |Build Status| image:: https://travis-ci.org/iambrandontaylor/django-admin-sortable.svg?branch=master
+   :target: https://travis-ci.org/iambrandontaylor/django-admin-sortable
diff --git a/adminsortable/__init__.py b/adminsortable/__init__.py
new file mode 100644
index 0000000..25cbabc
--- /dev/null
+++ b/adminsortable/__init__.py
@@ -0,0 +1,17 @@
+VERSION = (2, 0, 10)
+DEV_N = None
+
+
+def get_version():
+    version = '{0}.{1}'.format(VERSION[0], VERSION[1])
+    if VERSION[2]:
+        version = '{0}.{1}'.format(version, VERSION[2])
+    try:
+        if VERSION[3]:
+            version = '{0}.{1}'.format(version, VERSION[3])
+    except IndexError:
+        pass
+    return version
+
+
+__version__ = get_version()
diff --git a/adminsortable/admin.py b/adminsortable/admin.py
new file mode 100755
index 0000000..123e9a7
--- /dev/null
+++ b/adminsortable/admin.py
@@ -0,0 +1,371 @@
+import json
+
+from django import VERSION
+
+from django.conf import settings
+
+if VERSION > (1, 7):
+    from django.conf.urls import url
+elif VERSION > (1, 5):
+    from django.conf.urls import patterns, url
+else:
+    from django.conf.urls.defaults import patterns, url
+
+from django.contrib.admin import ModelAdmin, TabularInline, StackedInline
+from django.contrib.admin.options import InlineModelAdmin
+
+if VERSION >= (1, 8):
+    from django.contrib.auth import get_permission_codename
+    from django.contrib.contenttypes.admin import (GenericStackedInline,
+        GenericTabularInline)
+else:
+    from django.contrib.contenttypes.generic import (GenericStackedInline,
+        GenericTabularInline)
+
+from django.contrib.contenttypes.models import ContentType
+from django.http import HttpResponse
+from django.shortcuts import render
+from django.template.defaultfilters import capfirst
+
+from adminsortable.fields import SortableForeignKey
+from adminsortable.models import SortableMixin
+from adminsortable.utils import get_is_sortable
+
+STATIC_URL = settings.STATIC_URL
+
+
+class SortableAdminBase(object):
+    sortable_change_list_with_sort_link_template = \
+        'adminsortable/change_list_with_sort_link.html'
+    sortable_change_form_template = 'adminsortable/change_form.html'
+    sortable_change_list_template = 'adminsortable/change_list.html'
+
+    change_form_template_extends = 'admin/change_form.html'
+    change_list_template_extends = 'admin/change_list.html'
+
+    def changelist_view(self, request, extra_context=None):
+        """
+        If the model that inherits Sortable has more than one object,
+        its sort order can be changed. This view adds a link to the
+        object_tools block to take people to the view to change the sorting.
+        """
+
+        try:
+            qs_method = getattr(self, 'get_queryset', self.queryset)
+        except AttributeError:
+            qs_method = self.get_queryset
+
+        if get_is_sortable(qs_method(request)):
+            self.change_list_template = \
+                self.sortable_change_list_with_sort_link_template
+            self.is_sortable = True
+
+        if extra_context is None:
+            extra_context = {}
+
+        extra_context.update({
+            'change_list_template_extends': self.change_list_template_extends,
+            'sorting_filters': [sort_filter[0] for sort_filter
+                in getattr(self.model, 'sorting_filters', [])]
+        })
+        return super(SortableAdminBase, self).changelist_view(request,
+            extra_context=extra_context)
+
+
+class SortableAdmin(SortableAdminBase, ModelAdmin):
+    """
+    Admin class to add template overrides and context objects to enable
+    drag-and-drop ordering.
+    """
+
+    class Meta:
+        abstract = True
+
+    def get_urls(self):
+        urls = super(SortableAdmin, self).get_urls()
+
+        # this ajax view changes the order
+        admin_do_sorting_url = url(r'^sorting/do-sorting/(?P<model_type_id>\d+)/$',
+            self.admin_site.admin_view(self.do_sorting_view),
+            name='admin_do_sorting')
+
+        # this view displays the sortable objects
+        admin_sort_url = url(r'^sort/$',
+            self.admin_site.admin_view(self.sort_view),
+            name='admin_sort')
+
+        if VERSION > (1, 7):
+            admin_urls = [
+                admin_do_sorting_url,
+                admin_sort_url
+            ]
+        else:
+            admin_urls = patterns('',
+                admin_do_sorting_url,
+                admin_sort_url,)
+
+        return admin_urls + urls
+
+    def sort_view(self, request):
+        """
+        Custom admin view that displays the objects as a list whose sort
+        order can be changed via drag-and-drop.
+        """
+
+        opts = self.model._meta
+        if VERSION >= (1, 8):
+            codename = get_permission_codename('change', opts)
+            has_perm = request.user.has_perm('{0}.{1}'.format(opts.app_label,
+                codename))
+        else:
+            has_perm = request.user.has_perm('{0}.{1}'.format(opts.app_label,
+                opts.get_change_permission()))
+
+        jquery_lib_path = 'admin/js/jquery.js' if VERSION < (1, 9) \
+            else 'admin/js/vendor/jquery/jquery.js'
+
+        # get sort group index from querystring if present
+        sort_filter_index = request.GET.get('sort_filter')
+
+        filters = {}
+        if sort_filter_index:
+            try:
+                filters = self.model.sorting_filters[int(sort_filter_index)][1]
+            except (IndexError, ValueError):
+                pass
+
+        # Apply any sort filters to create a subset of sortable objects
+        try:
+            qs_method = getattr(self, 'get_queryset', self.queryset)
+        except AttributeError:
+            qs_method = self.get_queryset
+        objects = qs_method(request).filter(**filters)
+
+        # Determine if we need to regroup objects relative to a
+        # foreign key specified on the model class that is extending Sortable.
+        # Legacy support for 'sortable_by' defined as a model property
+        sortable_by_property = getattr(self.model, 'sortable_by', None)
+
+        # see if our model is sortable by a SortableForeignKey field
+        # and that the number of objects available is >= 2
+        sortable_by_fk = None
+        sortable_by_field_name = None
+        sortable_by_class_is_sortable = False
+
+        for field in self.model._meta.fields:
+            if isinstance(field, SortableForeignKey):
+                sortable_by_fk = field.rel.to
+                sortable_by_field_name = field.name.lower()
+                sortable_by_class_is_sortable = sortable_by_fk.objects.count() >= 2
+
+        if sortable_by_property:
+            # backwards compatibility for < 1.1.1, where sortable_by was a
+            # classmethod instead of a property
+            try:
+                sortable_by_class, sortable_by_expression = \
+                    sortable_by_property()
+            except (TypeError, ValueError):
+                sortable_by_class = self.model.sortable_by
+                sortable_by_expression = sortable_by_class.__name__.lower()
+
+            sortable_by_class_display_name = sortable_by_class._meta \
+                .verbose_name_plural
+
+        elif sortable_by_fk:
+            # get sortable by properties from the SortableForeignKey
+            # field - supported in 1.3+
+            sortable_by_class_display_name = sortable_by_fk._meta.verbose_name_plural
+            sortable_by_class = sortable_by_fk
+            sortable_by_expression = sortable_by_field_name
+
+        else:
+            # model is not sortable by another model
+            sortable_by_class = sortable_by_expression = \
+                sortable_by_class_display_name = \
+                sortable_by_class_is_sortable = None
+
+        if sortable_by_property or sortable_by_fk:
+            # Order the objects by the property they are sortable by,
+            # then by the order, otherwise the regroup
+            # template tag will not show the objects correctly
+
+            try:
+                order_field_name = opts.model._meta.ordering[0]
+            except (AttributeError, IndexError):
+                # for Django 1.5.x
+                order_field_name = opts.ordering[0]
+            finally:
+                order_field_name = 'order'
+
+            objects = objects.order_by(sortable_by_expression, order_field_name)
+
+        try:
+            verbose_name_plural = opts.verbose_name_plural.__unicode__()
+        except AttributeError:
+            verbose_name_plural = opts.verbose_name_plural
+
+        context = {
+            'title': u'Drag and drop {0} to change display order'.format(
+                capfirst(verbose_name_plural)),
+            'opts': opts,
+            'app_label': opts.app_label,
+            'has_perm': has_perm,
+            'objects': objects,
+            'group_expression': sortable_by_expression,
+            'sortable_by_class': sortable_by_class,
+            'sortable_by_class_is_sortable': sortable_by_class_is_sortable,
+            'sortable_by_class_display_name': sortable_by_class_display_name,
+            'jquery_lib_path': jquery_lib_path
+        }
+        return render(request, self.sortable_change_list_template, context)
+
+    def add_view(self, request, form_url='', extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+
+        extra_context.update({
+            'change_form_template_extends': self.change_form_template_extends
+        })
+        return super(SortableAdmin, self).add_view(request, form_url,
+            extra_context=extra_context)
+
+    def change_view(self, request, object_id, form_url='', extra_context=None):
+        self.has_sortable_tabular_inlines = False
+        self.has_sortable_stacked_inlines = False
+
+        if extra_context is None:
+            extra_context = {}
+
+        extra_context.update({
+            'change_form_template_extends': self.change_form_template_extends
... 2312 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django-adminsortable.git



More information about the Python-modules-commits mailing list