├── adminsortable ├── templatetags │ ├── __init__.py │ └── django_template_additions.py ├── locale │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── hr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── nb │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── nl │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── pl │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── ru │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── uk │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── pt_BR │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ └── django.po │ └── lv │ │ └── LC_MESSAGES │ │ └── django.po ├── templates │ └── adminsortable │ │ ├── shared │ │ ├── objects.html │ │ ├── list_items.html │ │ ├── object_rep.html │ │ └── nested_objects.html │ │ ├── change_list_with_sort_link.html │ │ ├── csrf │ │ └── jquery.django-csrf.html │ │ ├── change_form.html │ │ ├── admin.sortable.html │ │ ├── edit_inline │ │ ├── stacked.html │ │ ├── admin.sortable.stacked.inlines.html │ │ ├── admin.sortable.tabular.inlines.html │ │ └── tabular.html │ │ └── change_list.html ├── static │ └── adminsortable │ │ ├── css │ │ ├── admin.sortable.inline.css │ │ └── admin.sortable.css │ │ └── js │ │ └── jquery.ui.touch-punch.min.js ├── fields.py ├── __init__.py ├── utils.py └── models.py ├── sample_project ├── samples │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0004_project_isfunded.py │ │ ├── 0003_project_isapproved.py │ │ └── 0002_auto_20180319_2117.py │ ├── apps.py │ └── admin.py ├── sample_project │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── database │ └── test_project.sqlite ├── manage.py └── templates │ └── adminsortable │ ├── custom_change_form.html │ └── custom_change_list.html ├── setup.cfg ├── AUTHORS ├── docs ├── status.rst ├── license.rst ├── _build │ ├── html │ │ ├── objects.inv │ │ ├── _sources │ │ │ ├── status.txt │ │ │ ├── license.txt │ │ │ ├── future.txt │ │ │ ├── known-issues.txt │ │ │ ├── testing.txt │ │ │ ├── rationale.txt │ │ │ ├── configuration.txt │ │ │ ├── quickstart.txt │ │ │ ├── index.txt │ │ │ └── django-cms.txt │ │ ├── _static │ │ │ ├── up.png │ │ │ ├── down.png │ │ │ ├── file.png │ │ │ ├── minus.png │ │ │ ├── plus.png │ │ │ ├── comment.png │ │ │ ├── ajax-loader.gif │ │ │ ├── up-pressed.png │ │ │ ├── comment-close.png │ │ │ ├── down-pressed.png │ │ │ ├── comment-bright.png │ │ │ ├── fonts │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ └── fontawesome-webfont.woff │ │ │ ├── js │ │ │ │ └── theme.js │ │ │ ├── css │ │ │ │ └── badge_only.css │ │ │ ├── pygments.css │ │ │ ├── default.css │ │ │ ├── sidebar.js │ │ │ └── doctools.js │ │ ├── .buildinfo │ │ ├── searchindex.js │ │ ├── genindex.html │ │ ├── testing.html │ │ ├── status.html │ │ ├── known-issues.html │ │ ├── search.html │ │ ├── license.html │ │ ├── future.html │ │ ├── configuration.html │ │ └── rationale.html │ └── doctrees │ │ ├── future.doctree │ │ ├── index.doctree │ │ ├── status.doctree │ │ ├── usage.doctree │ │ ├── license.doctree │ │ ├── testing.doctree │ │ ├── django-cms.doctree │ │ ├── environment.pickle │ │ ├── quickstart.doctree │ │ ├── rationale.doctree │ │ ├── configuration.doctree │ │ └── known-issues.doctree ├── future.rst ├── known-issues.rst ├── testing.rst ├── rationale.rst ├── configuration.rst ├── quickstart.rst ├── index.rst ├── django-cms.rst └── Makefile ├── MANIFEST.in ├── .vscode └── settings.json ├── .gitignore ├── COPYRIGHT ├── tox.ini ├── setup.py └── .github └── workflows └── tests.yml /adminsortable/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sample_project/samples/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sample_project/sample_project/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_date = 0 3 | -------------------------------------------------------------------------------- /sample_project/samples/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | This software is maintained by: 2 | Brandon Taylor 3 | -------------------------------------------------------------------------------- /docs/status.rst: -------------------------------------------------------------------------------- 1 | Status 2 | ====== 3 | 4 | django-admin-sortable is stable and currently used in production. 5 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | django-admin-sortable is released under the Apache Public License v2. 5 | -------------------------------------------------------------------------------- /docs/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/objects.inv -------------------------------------------------------------------------------- /docs/_build/html/_sources/status.txt: -------------------------------------------------------------------------------- 1 | Status 2 | ====== 3 | 4 | django-admin-sortable is stable and currently used in production. 5 | -------------------------------------------------------------------------------- /docs/_build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/up.png -------------------------------------------------------------------------------- /docs/_build/doctrees/future.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/future.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/status.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/status.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/usage.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/usage.doctree -------------------------------------------------------------------------------- /docs/_build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/down.png -------------------------------------------------------------------------------- /docs/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/file.png -------------------------------------------------------------------------------- /docs/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/doctrees/license.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/license.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/testing.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/testing.doctree -------------------------------------------------------------------------------- /docs/_build/html/_sources/license.txt: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | django-admin-sortable is released under the Apache Public License v2. 5 | -------------------------------------------------------------------------------- /docs/_build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/comment.png -------------------------------------------------------------------------------- /sample_project/samples/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SamplesConfig(AppConfig): 5 | name = 'samples' 6 | -------------------------------------------------------------------------------- /docs/_build/doctrees/django-cms.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/django-cms.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/doctrees/quickstart.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/quickstart.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/rationale.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/rationale.doctree -------------------------------------------------------------------------------- /docs/_build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_build/doctrees/configuration.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/configuration.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/known-issues.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/doctrees/known-issues.doctree -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /adminsortable/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/hr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/hr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/nb/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/nb/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/pl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/pl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /adminsortable/locale/uk/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/uk/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /sample_project/database/test_project.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/sample_project/database/test_project.sqlite -------------------------------------------------------------------------------- /adminsortable/locale/pt_BR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/adminsortable/locale/pt_BR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include adminsortable/static * 2 | recursive-include adminsortable/templates * 3 | recursive-include adminsortable/locale * 4 | prune sample_project -------------------------------------------------------------------------------- /docs/_build/html/_static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/_build/html/_static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/_build/html/_static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jazzband/django-admin-sortable/master/docs/_build/html/_static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/Users/btaylor/virtualenvs/django-admin-sortable/bin/python", 3 | "python.linting.pylintPath": "/Users/btaylor/virtualenvs/django-admin-sortable/bin/pylint" 4 | } 5 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/shared/objects.html: -------------------------------------------------------------------------------- 1 | {% if objects %} 2 | 5 | {% endif %} -------------------------------------------------------------------------------- /docs/future.rst: -------------------------------------------------------------------------------- 1 | Future Plans 2 | ============ 3 | 4 | - Support for foreign keys that are self referential 5 | - Move unit tests out of sample project (I could really use some help with this one) 6 | - Travis CI integration 7 | -------------------------------------------------------------------------------- /adminsortable/static/adminsortable/css/admin.sortable.inline.css: -------------------------------------------------------------------------------- 1 | .sortable.has_original { 2 | cursor: move; 3 | } 4 | 5 | .sortable .inline-related h3 .fa, 6 | .sortable.inline-group .module .fa { 7 | margin-right: 5px; 8 | } 9 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/future.txt: -------------------------------------------------------------------------------- 1 | Future Plans 2 | ============ 3 | 4 | - Support for foreign keys that are self referential 5 | - Move unit tests out of sample project (I could really use some help with this one) 6 | - Travis CI integration 7 | -------------------------------------------------------------------------------- /docs/known-issues.rst: -------------------------------------------------------------------------------- 1 | Known Issue(s) 2 | ============== 3 | 4 | Because of the way inline models are added to their parent model in the change form, it is not currently possible to have sortable inline models whose parent does not inhert from ``Sortable``. 5 | -------------------------------------------------------------------------------- /docs/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 330c9fec598c1d7c8412fdb0eeacc632 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/known-issues.txt: -------------------------------------------------------------------------------- 1 | Known Issue(s) 2 | ============== 3 | 4 | Because of the way inline models are added to their parent model in the change form, it is not currently possible to have sortable inline models whose parent does not inhert from ``Sortable``. 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | dist 3 | django_admin_sortable.egg-info 4 | .pydevproject 5 | *.pyc 6 | *.pyo 7 | .idea 8 | atlassian-* 9 | *.sublime-* 10 | .ropeproject 11 | .codeintel 12 | __pycache__ 13 | .venv/ 14 | .coverage 15 | .tox/ 16 | htmlcov/ 17 | build 18 | .vscode/* 19 | -------------------------------------------------------------------------------- /adminsortable/fields.py: -------------------------------------------------------------------------------- 1 | from django.db.models.fields.related import ForeignKey 2 | 3 | 4 | class SortableForeignKey(ForeignKey): 5 | """ 6 | Field simply acts as a flag to determine the class to sort by. 7 | This field replaces previous functionality where `sortable_by` was 8 | defined as a model property that specified another model class. 9 | """ 10 | pass 11 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | (c) Copyright 2011 Brandon Taylor - I Am Brandon Taylor 2 | 3 | django-admin-sortable is free software: you can 4 | redistribute it and/or modify it under 5 | the terms of the Apache Public License v2. 6 | 7 | django-admin-sortable is distributed in the hope 8 | that it will be useful, but WITHOUT ANY 9 | WARRANTY; without even the implied 10 | warranty of MERCHANTABILITY or FITNESS 11 | FOR A PARTICULAR PURPOSE. 12 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/shared/list_items.html: -------------------------------------------------------------------------------- 1 | {% with list_objects_length=list_objects|length %} 2 | {% for object in list_objects %} 3 |
  • 4 | {% if list_objects_length > 1 %} 5 | {% include "adminsortable/shared/object_rep.html" %} 6 | {% else %} 7 | {{ object }} 8 | {% endif %} 9 |
  • 10 | {% endfor %} 11 | {% endwith %} 12 | -------------------------------------------------------------------------------- /adminsortable/__init__.py: -------------------------------------------------------------------------------- 1 | VERSION = (2, 3, 0) 2 | DEV_N = None 3 | 4 | 5 | def get_version(): 6 | version = '{0}.{1}'.format(VERSION[0], VERSION[1]) 7 | if VERSION[2]: 8 | version = '{0}.{1}'.format(version, VERSION[2]) 9 | try: 10 | if VERSION[3]: 11 | version = '{0}.{1}'.format(version, VERSION[3]) 12 | except IndexError: 13 | pass 14 | return version 15 | 16 | 17 | __version__ = get_version() 18 | -------------------------------------------------------------------------------- /sample_project/sample_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django2_app project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ 8 | """ 9 | import os 10 | 11 | from django.core.wsgi import get_wsgi_application 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings") 14 | application = get_wsgi_application() 15 | 16 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/shared/object_rep.html: -------------------------------------------------------------------------------- 1 | {% load admin_urls l10n %} 2 | 3 |
    4 | 5 | {{ object }} 6 | {% csrf_token %} 7 |
    8 | -------------------------------------------------------------------------------- /sample_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | # Adds the adminsortable package from the cloned repository instead of 6 | # site_packages 7 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 8 | 9 | if __name__ == "__main__": 10 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample_project.settings") 11 | 12 | from django.core.management import execute_from_command_line 13 | 14 | execute_from_command_line(sys.argv) 15 | -------------------------------------------------------------------------------- /sample_project/samples/migrations/0004_project_isfunded.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-10-06 13:01 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('samples', '0003_project_isapproved'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='project', 15 | name='isFunded', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /sample_project/samples/migrations/0003_project_isapproved.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-10-06 12:57 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('samples', '0002_auto_20180319_2117'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='project', 15 | name='isApproved', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /sample_project/templates/adminsortable/custom_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "adminsortable/change_form.html" %} 2 | 3 | {% block extrahead %} 4 | {{ block.super }} 5 | 6 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /sample_project/templates/adminsortable/custom_change_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminsortable/change_list.html' %} 2 | 3 | {% block extrahead %} 4 | {{ block.super }} 5 | 6 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/testing.txt: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | Have a look at the included :doc:`/sample_project` directory to see a working project. The login credentials for admin are: admin/admin 5 | 6 | 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. 7 | 8 | Inlines may be drag-and-dropped into any order directly from the change form. 9 | 10 | Unit and functional tests may be found in the ``app/tests.py`` file and run via: 11 | 12 | $ python manage.py test app 13 | -------------------------------------------------------------------------------- /docs/testing.rst: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | Have a look at the included :doc:`/sample_project` directory to see a working project. The login credentials for admin are: admin/admin 5 | 6 | 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. 7 | 8 | Inlines may be drag-and-dropped into any order directly from the change form. 9 | 10 | Unit and functional tests may be found in the ``app/tests.py`` file and run via: 11 | 12 | .. code-block:: bash 13 | 14 | $ python manage.py test app 15 | -------------------------------------------------------------------------------- /docs/rationale.rst: -------------------------------------------------------------------------------- 1 | Rationale 2 | ========= 3 | 4 | Why another drag-and-drop ordering plugin? 5 | ------------------------------------------ 6 | 7 | Other projects have added drag-and-drop ordering to the ChangeList view, however this introduces a couple of problems... 8 | 9 | - The ChangeList view supports pagination, which makes drag-and-drop ordering across pages impossible. 10 | - 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. 11 | - The ChangeList supports in-line editing, and adding drag-and-drop ordering on top of that just seemed a little much in my opinion. 12 | -------------------------------------------------------------------------------- /docs/configuration.rst: -------------------------------------------------------------------------------- 1 | Configuring Django Admin Sortable 2 | ================================= 3 | 4 | Configuring django-admin-sortable is quite simple: 5 | 6 | 1. Add ``adminsortable`` to your ``INSTALLED_APPS``. 7 | 2. Ensure ``django.core.context_processors.static`` is in your ``TEMPLATE_CONTEXT_PROCESSORS``. 8 | 9 | Static Media 10 | ------------ 11 | 12 | django-admin-sortable includes a few CSS and JavaScript files. The preferred method of getting these files into your project is to use the `staticfiles app `_. 13 | 14 | Alternatively, you can copy or symlink the ``adminsortable`` folder inside the ``static`` directory to the location you serve static files from. 15 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/rationale.txt: -------------------------------------------------------------------------------- 1 | Rationale 2 | ========= 3 | 4 | Why another drag-and-drop ordering plugin? 5 | ------------------------------------------ 6 | 7 | Other projects have added drag-and-drop ordering to the ChangeList view, however this introduces a couple of problems... 8 | 9 | - The ChangeList view supports pagination, which makes drag-and-drop ordering across pages impossible. 10 | - 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. 11 | - The ChangeList supports in-line editing, and adding drag-and-drop ordering on top of that just seemed a little much in my opinion. 12 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/configuration.txt: -------------------------------------------------------------------------------- 1 | Configuring Django Admin Sortable 2 | ================================= 3 | 4 | Configuring django-admin-sortable is quite simple: 5 | 6 | 1. Add ``adminsortable`` to your ``INSTALLED_APPS``. 7 | 2. Ensure ``django.core.context_processors.static`` is in your ``TEMPLATE_CONTEXT_PROCESSORS``. 8 | 9 | Static Media 10 | ------------ 11 | 12 | django-admin-sortable includes a few CSS and JavaScript files. The preferred method of getting these files into your project is to use the `staticfiles app `_. 13 | 14 | Alternatively, you can copy or symlink the ``adminsortable`` folder inside the ``static`` directory to the location you serve static files from. 15 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = django{2.2,3.1,3.2}-{py36,py37,py38,py39},coverage 3 | 4 | [testenv] 5 | deps = 6 | coverage 7 | django2.2: Django>=2.2 8 | django3.1: Django>=3.1 9 | django3.2: Django>=3.2 10 | whitelist_externals = cd 11 | setenv = 12 | PYTHONPATH = {toxinidir}/sample_project 13 | PYTHONWARNINGS = module 14 | PYTHONDONTWRITEBYTECODE = 1 15 | commands = 16 | coverage run -p sample_project/manage.py test samples 17 | 18 | [testenv:coverage] 19 | deps = coverage 20 | skip_install = true 21 | commands = 22 | coverage combine 23 | coverage report 24 | coverage html 25 | 26 | [coverage:run] 27 | branch = True 28 | parallel = True 29 | source = 30 | adminsortable 31 | sample_project 32 | 33 | [coverage:report] 34 | exclude_lines = 35 | if __name__ == .__main__.: 36 | -------------------------------------------------------------------------------- /sample_project/sample_project/urls.py: -------------------------------------------------------------------------------- 1 | """django2_app URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /sample_project/samples/migrations/0002_auto_20180319_2117.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0 on 2018-03-20 01:17 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('samples', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='TestNonAutoFieldModel', 16 | fields=[ 17 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 18 | ('order', models.PositiveIntegerField(db_index=True, editable=False)), 19 | ], 20 | options={ 21 | 'ordering': ['order'], 22 | }, 23 | ), 24 | migrations.AlterField( 25 | model_name='category', 26 | name='order', 27 | field=models.PositiveIntegerField(default=0, editable=False), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /adminsortable/utils.py: -------------------------------------------------------------------------------- 1 | from .models import SortableMixin, SortableForeignKey 2 | 3 | 4 | def check_inheritance(cls): 5 | return issubclass(type(cls), SortableMixin) 6 | 7 | 8 | def get_is_sortable(objects): 9 | if objects.count() < 2: 10 | return False 11 | 12 | if not check_inheritance(objects[:1][0]): 13 | return False 14 | 15 | return True 16 | 17 | 18 | def is_self_referential(cls): 19 | cls_type = type(cls) 20 | sortable_subclass = check_inheritance(cls_type) 21 | sortable_foreign_key_subclass = issubclass(cls_type, SortableForeignKey) 22 | if sortable_foreign_key_subclass and not sortable_subclass: 23 | return True 24 | return False 25 | 26 | 27 | def check_model_is_sortable(cls): 28 | if cls: 29 | if check_inheritance(cls): 30 | if is_self_referential(cls): 31 | objects = cls.model.objects 32 | else: 33 | objects = cls.objects 34 | return get_is_sortable(objects.all()) 35 | return False 36 | -------------------------------------------------------------------------------- /adminsortable/static/adminsortable/css/admin.sortable.css: -------------------------------------------------------------------------------- 1 | #sortable ul 2 | { 3 | -webkit-padding-start: 0; 4 | padding-left: 0; 5 | margin-top: 0.75em; 6 | } 7 | 8 | #sortable ul ul 9 | { 10 | margin-left: 1em; 11 | } 12 | 13 | #sortable ul.sortable li, 14 | #sortable ul.sortable li a 15 | { 16 | cursor: move; 17 | } 18 | 19 | #sortable ul li 20 | { 21 | overflow: auto; 22 | margin-bottom: 8px; 23 | margin-left: 0; 24 | display: block; 25 | } 26 | 27 | #sortable ul li:last-child { 28 | margin-bottom: 0; 29 | } 30 | 31 | #sortable .sortable 32 | { 33 | list-style: none; 34 | font-weight: 800; 35 | margin-bottom: 0.75em; 36 | } 37 | 38 | #sortable .sortable.single, 39 | #sortable ul ul a 40 | { 41 | font-weight: 400; 42 | } 43 | 44 | #sortable ul ul a 45 | { 46 | color: #5B80B2; 47 | margin-bottom: 0; 48 | } 49 | 50 | .sortable-help-text { 51 | color: #999; 52 | font-size: 13px; 53 | } 54 | 55 | .sortable a:hover 56 | { 57 | color: #003366; 58 | } 59 | 60 | .sortable .fa { 61 | margin-right: 7px; 62 | } 63 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/change_list_with_sort_link.html: -------------------------------------------------------------------------------- 1 | {% extends change_list_template_extends %} 2 | {% load i18n %} 3 | 4 | {% block extrahead %} 5 | {{ block.super }} 6 | 18 | {% endblock %} 19 | 20 | 21 | {% block object-tools-items %} 22 | {% for sorting_filter in sorting_filters %} 23 |
  • 24 | {% trans 'Change Order of' %} {{ sorting_filter }} 25 |
  • 26 | {% empty %} 27 | {% if is_sortable %} 28 |
  • 29 | {% trans 'Change Order' %} 30 |
  • 31 | {% endif %} 32 | {% endfor %} 33 | {{ block.super }} 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('README.rst', encoding='utf8') as readme_file: 4 | README = readme_file.read() 5 | 6 | setup( 7 | author='Brandon Taylor', 8 | author_email='alsoicode@gmail.com', 9 | classifiers=['Development Status :: 5 - Production/Stable', 10 | 'Environment :: Web Environment', 11 | 'Framework :: Django', 12 | 'Intended Audience :: Developers', 13 | 'License :: OSI Approved :: Apache Software License', 14 | 'Operating System :: OS Independent', 15 | 'Programming Language :: Python :: 3', 16 | 'Topic :: Utilities'], 17 | description='Drag and drop sorting for models and inline models in Django admin.', 18 | include_package_data=True, 19 | install_requires=['django'], 20 | license='APL', 21 | long_description=README, 22 | name='django-admin-sortable', 23 | packages=find_packages(exclude=['sample_project']), 24 | url='https://github.com/iambrandontaylor/django-admin-sortable', 25 | version=__import__('adminsortable').__version__, 26 | zip_safe=False 27 | ) 28 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/quickstart.txt: -------------------------------------------------------------------------------- 1 | Quickstart 2 | ========== 3 | 4 | To get started using ``django-admin-sortable`` simply install it using ``pip``:: 5 | 6 | $ pip install django-admin-sortable 7 | 8 | Add ``adminsortable`` to your project's ``INSTALLED_APPS`` setting. 9 | 10 | Ensure ``django.core.context_processors.static`` is in your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. 11 | 12 | Define your model, inheriting from ``adminsortable.Sortable``:: 13 | 14 | # models.py 15 | from adminsortable.models import Sortable 16 | 17 | class MySortableClass(Sortable): 18 | class Meta(Sortable.Meta): 19 | pass 20 | 21 | title = models.CharField(max_length=50) 22 | 23 | def __unicode__(self): 24 | return self.title 25 | 26 | Wire up your sortable model to Django admin:: 27 | 28 | # admin.py 29 | from adminsortable.admin import SortableAdmin 30 | from .models import MySortableClass 31 | 32 | class MySortableAdminClass(SortableAdmin): 33 | """Any admin options you need go here""" 34 | 35 | admin.site.register(MySortableClass, MySortableAdminClass) 36 | 37 | Your model's ChangeList view should now have an extra tool link when there are 2 or more objects present that will take you to a view where you can drag-and-drop the objects into your desired order. 38 | -------------------------------------------------------------------------------- /adminsortable/static/adminsortable/js/jquery.ui.touch-punch.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI Touch Punch 0.2.3 3 | * 4 | * Copyright 2011–2014, Dave Furfero 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * 7 | * Depends: 8 | * jquery.ui.widget.js 9 | * jquery.ui.mouse.js 10 | */ 11 | !function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/csrf/jquery.django-csrf.html: -------------------------------------------------------------------------------- 1 | 35 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/shared/nested_objects.html: -------------------------------------------------------------------------------- 1 | {% load django_template_additions %} 2 | {% dynamic_regroup objects by group_expression as regrouped_objects %} 3 | {% if regrouped_objects %} 4 |
      5 | {% for regrouped_object in regrouped_objects %} 6 | {% with object=regrouped_object.grouper %} 7 | {% if object %} 8 |
    • {% if sortable_by_class_is_sortable %} 9 | {% include "adminsortable/shared/object_rep.html" %} 10 | {% else %} 11 | {{ object }} 12 | {% endif %} 13 | 14 | {% if regrouped_object.list %} 15 | {% with regrouped_object_list_length=regrouped_object.list|length %} 16 |
        1 %}class="sortable"{% endif %}> 17 | {% include "adminsortable/shared/list_items.html" with list_objects=regrouped_object.list %} 18 |
      19 | {% endwith %} 20 | {% endif %} 21 |
    • 22 | {% endif %} 23 | {% endwith %} 24 | {% endfor %} 25 |
    26 | {% endif %} 27 | -------------------------------------------------------------------------------- /adminsortable/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | #, fuzzy 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: adminsortable\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2011-09-22 15:42+0200\n" 7 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | 12 | #: templates/adminsortable/change_list.html:15 13 | #, python-format 14 | msgid "Drag and drop %(model)s to change display order" 15 | msgstr "" 16 | 17 | #: templates/adminsortable/change_list.html:25 18 | #, python-format 19 | msgid "Reorder" 20 | msgstr "" 21 | 22 | #: templates/adminsortable/change_list.html:32 23 | #, python-format 24 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 25 | msgstr "" 26 | 27 | #: templates/adminsortable/change_list.html:34 28 | #, python-format 29 | msgid "Drag and drop %(model)s to change their order." 30 | msgstr "" 31 | 32 | #: templates/adminsortable/change_list.html:39 33 | #, python-format 34 | msgid "" 35 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 36 | "their order." 37 | msgstr "" 38 | 39 | #: templates/adminsortable/change_list.html:50 40 | #, python-format 41 | msgid "Return to %(model)s" 42 | msgstr "" 43 | 44 | #: templates/adminsortable/change_list_with_sort_link.html:6 45 | msgid "Change Order" 46 | msgstr "" 47 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | Quickstart 2 | ========== 3 | 4 | To get started using ``django-admin-sortable`` simply install it using ``pip``:: 5 | 6 | .. code-block:: bash 7 | 8 | $ pip install django-admin-sortable 9 | 10 | Add ``adminsortable`` to your project's ``INSTALLED_APPS`` setting. 11 | 12 | Ensure ``django.core.context_processors.static`` is in your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. 13 | 14 | Define your model, inheriting from ``adminsortable.Sortable``:: 15 | 16 | .. code-block:: python 17 | 18 | # models.py 19 | from adminsortable.models import Sortable 20 | 21 | class MySortableClass(Sortable): 22 | class Meta(Sortable.Meta): 23 | pass 24 | 25 | title = models.CharField(max_length=50) 26 | 27 | def __unicode__(self): 28 | return self.title 29 | 30 | Wire up your sortable model to Django admin:: 31 | 32 | .. code-block:: python 33 | 34 | # admin.py 35 | from adminsortable.admin import SortableAdmin 36 | from .models import MySortableClass 37 | 38 | class MySortableAdminClass(SortableAdmin): 39 | """Any admin options you need go here""" 40 | 41 | admin.site.register(MySortableClass, MySortableAdminClass) 42 | 43 | Your model's ChangeList view should now have an extra tool link when there are 2 or more objects present that will take you to a view where you can drag-and-drop the objects into your desired order. 44 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tests 3 | 4 | on: 5 | push: 6 | branches: 7 | - develop 8 | - master 9 | pull_request: 10 | 11 | jobs: 12 | tests: 13 | name: Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }} 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | python-version: 19 | - "3.6" 20 | - "3.7" 21 | - "3.8" 22 | - "3.9" 23 | django-version: 24 | - "2.2.17" # first version to support Python 3.9 25 | - "3.1.3" # first version to support Python 3.9 26 | - "3.2.0" 27 | include: 28 | - python-version: "3.8" 29 | django-version: "4.0.0" 30 | - python-version: "3.9" 31 | django-version: "4.0.0" 32 | - python-version: "3.10" 33 | django-version: "3.2.9" # first version to support Python 3.10 34 | - python-version: "3.10" 35 | django-version: "4.0.0" 36 | 37 | 38 | steps: 39 | - uses: actions/checkout@v2 40 | 41 | - name: Set up Python ${{ matrix.python-version }} 42 | uses: actions/setup-python@v2 43 | with: 44 | python-version: ${{ matrix.python-version }} 45 | 46 | - name: Install dependencies 47 | run: | 48 | python -m pip install --upgrade pip wheel setuptools 49 | python -m pip install --upgrade "django~=${{ matrix.django-version}}" 50 | - name: Run tests 51 | run: python manage.py test 52 | working-directory: sample_project 53 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Django Admin Sortable documentation master file, created by 2 | sphinx-quickstart on Wed Aug 20 14:40:56 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Django Admin Sortable's documentation! 7 | ================================================= 8 | 9 | Django Admin Sortable is a super-easy way to add drag-and-drop ordering to almost any model you manage through Django admin. Inlines for a sortable model may also be made sortable, enabling individual items or groups of items to be sortable. 10 | 11 | Supported Django Versions 12 | ------------------------- 13 | 14 | Django 1.4.x 15 | ^^^^^^^^^^^^ 16 | 17 | Use django-admin-sortable 1.4.9 or below. 18 | 19 | .. note:: 20 | 21 | v1.5.2 introduced backwards incompatible changes for Django 1.4.x 22 | 23 | Django >= 1.5.x 24 | ^^^^^^^^^^^^^^^^^^^^^^^ 25 | 26 | Use the latest version of django-admin-sortable. 27 | 28 | .. warning:: 29 | 30 | v1.6.6 introduced a backwards-incompatible change for ``sorting_filters``. Please update your ``sorting_filters`` attribute(s) to the new, tuple-based format. 31 | 32 | What's New in |version|? 33 | ------------------------ 34 | 35 | - Python 2.6 backwards compatibility. Thanks `@EnTeQuAk `_ 36 | 37 | 38 | Contents: 39 | --------- 40 | 41 | .. toctree:: 42 | :maxdepth: 3 43 | 44 | quickstart 45 | configuration 46 | usage 47 | django-cms 48 | known-issues 49 | testing 50 | rationale 51 | status 52 | future 53 | license 54 | 55 | Indices and tables 56 | ------------------ 57 | 58 | * :ref:`genindex` 59 | * :ref:`modindex` 60 | * :ref:`search` 61 | 62 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. Django Admin Sortable documentation master file, created by 2 | sphinx-quickstart on Wed Aug 20 14:40:56 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Django Admin Sortable's documentation! 7 | ================================================= 8 | 9 | Django Admin Sortable is a super-easy way to add drag-and-drop ordering to almost any model you manage through Django admin. Inlines for a sortable model may also be made sortable, enabling individual items or groups of items to be sortable. 10 | 11 | Supported Django Versions 12 | ------------------------- 13 | 14 | Django 1.4.x 15 | ^^^^^^^^^^^^ 16 | 17 | Use django-admin-sortable 1.4.9 or below. 18 | 19 | .. note:: 20 | 21 | v1.5.2 introduced backwards incompatible changes for Django 1.4.x 22 | 23 | Django >= 1.5.x 24 | ^^^^^^^^^^^^^^^^^^^^^^^ 25 | 26 | Use the latest version of django-admin-sortable. 27 | 28 | .. warning:: 29 | 30 | v1.6.6 introduced a backwards-incompatible change for ``sorting_filters``. Please update your ``sorting_filters`` attribute(s) to the new, tuple-based format. 31 | 32 | What's New in |version|? 33 | ------------------------ 34 | 35 | - Python 2.6 backwards compatibility. Thanks `@EnTeQuAk `_ 36 | 37 | 38 | Contents: 39 | --------- 40 | 41 | .. toctree:: 42 | :maxdepth: 3 43 | 44 | quickstart 45 | configuration 46 | usage 47 | django-cms 48 | known-issues 49 | testing 50 | rationale 51 | status 52 | future 53 | license 54 | 55 | Indices and tables 56 | ------------------ 57 | 58 | * :ref:`genindex` 59 | * :ref:`modindex` 60 | * :ref:`search` 61 | 62 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends change_form_template_extends %} 2 | {% load i18n admin_modify %} 3 | {% load static %} 4 | 5 | {% block extrahead %} 6 | {{ block.super }} 7 | {% url 'admin:jsi18n' as jsi18nurl %} 8 | 9 | {% if has_sortable_tabular_inlines or has_sortable_stacked_inlines %} 10 | 11 | 12 | {% include 'adminsortable/csrf/jquery.django-csrf.html' with csrf_cookie_name=csrf_cookie_name %} 13 | {% endif %} 14 | 15 | {% if has_sortable_tabular_inlines %} 16 | {% include 'adminsortable/edit_inline/admin.sortable.tabular.inlines.html' with after_sorting_js_callback_name=after_sorting_js_callback_name %} 17 | {% endif %} 18 | 19 | {% if has_sortable_stacked_inlines %} 20 | {% include 'adminsortable/edit_inline/admin.sortable.stacked.inlines.html' with after_sorting_js_callback_name=after_sorting_js_callback_name %} 21 | {% endif %} 22 | {% endblock %} 23 | 24 | {% block extrastyle %} 25 | {{ block.super }} 26 | {% if has_sortable_tabular_inlines or has_sortable_stacked_inlines %} 27 | 28 | 29 | {% endif %} 30 | {% endblock %} 31 | 32 | {% block after_related_objects %}{{ block.super }} 33 | 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /adminsortable/locale/nl/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: adminsortable\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2011-09-22 15:42+0200\n" 6 | "PO-Revision-Date: 2011-09-22 15:50+0100\n" 7 | "MIME-Version: 1.0\n" 8 | "Content-Type: text/plain; charset=UTF-8\n" 9 | "Content-Transfer-Encoding: 8bit\n" 10 | "Last-Translator: Jaap Roes \n" 11 | "Language-Team: \n" 12 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 13 | "X-Poedit-Language: Dutch\n" 14 | "X-Poedit-Country: NETHERLANDS\n" 15 | 16 | #: templates/adminsortable/change_list.html:15 17 | #, python-format 18 | msgid "Drag and drop %(model)s to change display order" 19 | msgstr "" 20 | 21 | #: templates/adminsortable/change_list.html:25 22 | #, python-format 23 | msgid "Reorder" 24 | msgstr "Reorder" 25 | 26 | #: templates/adminsortable/change_list.html:32 27 | #, python-format 28 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 29 | msgstr "Sleep %(sort_type)s %(model)s om de volgorde te veranderen" 30 | 31 | #: templates/adminsortable/change_list.html:34 32 | #, python-format 33 | msgid "Drag and drop %(model)s to change their order." 34 | msgstr "Sleep %(model)s om de volgorde te veranderen" 35 | 36 | #: templates/adminsortable/change_list.html:39 37 | #, python-format 38 | msgid "You may also drag and drop %(sortable_by_class_display_name)s to change their order." 39 | msgstr "U kunt ook %(sortable_by_class_display_name)s slepen om de volgorde te veranderen." 40 | 41 | #: templates/adminsortable/change_list.html:50 42 | #, python-format 43 | msgid "Return to %(model)s" 44 | msgstr "Terug naar %(model)s" 45 | 46 | #: templates/adminsortable/change_list_with_sort_link.html:6 47 | msgid "Change Order" 48 | msgstr "Volgorde veranderen" 49 | 50 | -------------------------------------------------------------------------------- /adminsortable/locale/hr/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | #, fuzzy 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: adminsortable\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2018-03-22 18:35+0100\n" 7 | "PO-Revision-Date: 2018-03-22 18:35+0100\n" 8 | "Last-Translator: Luka Matijevic \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Language: hr\n" 13 | 14 | #: templates/adminsortable/change_list.html:15 15 | #, python-format 16 | msgid "Drag and drop %(model)s to change display order" 17 | msgstr "Povuci i ispusti %(model)s kako bi promijenio redoslijed prikaza" 18 | 19 | #: templates/adminsortable/change_list.html:25 20 | #, python-format 21 | msgid "Reorder" 22 | msgstr "Promijeni redoslijed" 23 | 24 | #: templates/adminsortable/change_list.html:32 25 | #, python-format 26 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 27 | msgstr "Povuci i ispusti %(sort_type)s %(model)s kako bi promijenio njihov redoslijed." 28 | 29 | #: templates/adminsortable/change_list.html:34 30 | #, python-format 31 | msgid "Drag and drop %(model)s to change their order." 32 | msgstr "Povuci i ispusti %(model)s kako bi promijenio njihov redoslijed." 33 | 34 | #: templates/adminsortable/change_list.html:39 35 | #, python-format 36 | msgid "" 37 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 38 | "their order." 39 | msgstr "" 40 | "Možeš povući i ispustiti %(sortable_by_class_display_name)s kako bi promijenio " 41 | "njihov redoslijed." 42 | 43 | #: templates/adminsortable/change_list.html:50 44 | #, python-format 45 | msgid "Return to %(model)s" 46 | msgstr "Povratak na %(model)s" 47 | 48 | #: templates/adminsortable/change_list_with_sort_link.html:6 49 | msgid "Change Order" 50 | msgstr "Promjena redoslijeda" -------------------------------------------------------------------------------- /adminsortable/locale/nb/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: adminsortable\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2011-09-22 15:42+0200\n" 6 | "PO-Revision-Date: 2018-02-05 17:24+0100\n" 7 | "MIME-Version: 1.0\n" 8 | "Content-Type: text/plain; charset=UTF-8\n" 9 | "Content-Transfer-Encoding: 8bit\n" 10 | "Last-Translator: Simen Heggestøyl \n" 11 | "Language-Team: \n" 12 | "Language: nb\n" 13 | "X-Generator: Poedit 2.0.5\n" 14 | 15 | #: templates/adminsortable/change_list.html:15 16 | #, python-format 17 | msgid "Drag and drop %(model)s to change display order" 18 | msgstr "Dra og slipp %(model)s for å endre visningsrekkefølgen" 19 | 20 | #: templates/adminsortable/change_list.html:25 21 | #, python-format 22 | msgid "Reorder" 23 | msgstr "Endre rekkefølge" 24 | 25 | #: templates/adminsortable/change_list.html:32 26 | #, python-format 27 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 28 | msgstr "Dra og slipp %(sort_type)s %(model)s for å endre rekkefølgen deres." 29 | 30 | #: templates/adminsortable/change_list.html:34 31 | #, python-format 32 | msgid "Drag and drop %(model)s to change their order." 33 | msgstr "Dra og slipp %(model)s for å endre rekkefølgen deres." 34 | 35 | #: templates/adminsortable/change_list.html:39 36 | #, python-format 37 | msgid "" 38 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 39 | "their order." 40 | msgstr "" 41 | "Du kan også dra og slippe %(sortable_by_class_display_name)s for å endre " 42 | "rekkefølgen deres." 43 | 44 | #: templates/adminsortable/change_list.html:50 45 | #, python-format 46 | msgid "Return to %(model)s" 47 | msgstr "Tilbake til %(model)s" 48 | 49 | #: templates/adminsortable/change_list_with_sort_link.html:6 50 | msgid "Change Order" 51 | msgstr "Endre rekkefølge" 52 | -------------------------------------------------------------------------------- /adminsortable/locale/lv/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: adminsortable\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2011-09-22 15:42+0200\n" 6 | "PO-Revision-Date: 2018-02-08 22:47+0200\n" 7 | "MIME-Version: 1.0\n" 8 | "Content-Type: text/plain; charset=UTF-8\n" 9 | "Content-Transfer-Encoding: 8bit\n" 10 | "Last-Translator: Pēteris \n" 11 | "Language-Team: \n" 12 | "Language: lv\n" 13 | "X-Generator: Poedit 1.8.7.1\n" 14 | 15 | #: templates/adminsortable/change_list.html:15 16 | #, python-format 17 | msgid "Drag and drop %(model)s to change display order" 18 | msgstr "Velc un novieto %(model)s, lai mainītu attēlošanas secību" 19 | 20 | #: templates/adminsortable/change_list.html:25 21 | #, python-format 22 | msgid "Reorder" 23 | msgstr "Pārkārtot" 24 | 25 | #: templates/adminsortable/change_list.html:32 26 | #, python-format 27 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 28 | msgstr "Velc un novieto %(sort_type)s %(model)s, lai mainītu to secību." 29 | 30 | #: templates/adminsortable/change_list.html:34 31 | #, python-format 32 | msgid "Drag and drop %(model)s to change their order." 33 | msgstr "Velc un novieto %(model)s, lai mainītu attēlošanas secību." 34 | 35 | #: templates/adminsortable/change_list.html:39 36 | #, python-format 37 | msgid "" 38 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 39 | "their order." 40 | msgstr "" 41 | "Tu vari arī vilt un pārvieetot %(sortable_by_class_display_name)s, lai " 42 | "mainītu secību." 43 | 44 | #: templates/adminsortable/change_list.html:50 45 | #, python-format 46 | msgid "Return to %(model)s" 47 | msgstr "Atgriezties pie %(model)s" 48 | 49 | #: templates/adminsortable/change_list_with_sort_link.html:6 50 | msgid "Change Order" 51 | msgstr "Mainīt secību" 52 | -------------------------------------------------------------------------------- /docs/_build/html/_static/js/theme.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() { 2 | // Shift nav in mobile when clicking the menu. 3 | $(document).on('click', "[data-toggle='wy-nav-top']", function() { 4 | $("[data-toggle='wy-nav-shift']").toggleClass("shift"); 5 | $("[data-toggle='rst-versions']").toggleClass("shift"); 6 | }); 7 | // Close menu when you click a link. 8 | $(document).on('click', ".wy-menu-vertical .current ul li a", function() { 9 | $("[data-toggle='wy-nav-shift']").removeClass("shift"); 10 | $("[data-toggle='rst-versions']").toggleClass("shift"); 11 | }); 12 | $(document).on('click', "[data-toggle='rst-current-version']", function() { 13 | $("[data-toggle='rst-versions']").toggleClass("shift-up"); 14 | }); 15 | // Make tables responsive 16 | $("table.docutils:not(.field-list)").wrap("
    "); 17 | }); 18 | 19 | window.SphinxRtdTheme = (function (jquery) { 20 | var stickyNav = (function () { 21 | var navBar, 22 | win, 23 | stickyNavCssClass = 'stickynav', 24 | applyStickNav = function () { 25 | if (navBar.height() <= win.height()) { 26 | navBar.addClass(stickyNavCssClass); 27 | } else { 28 | navBar.removeClass(stickyNavCssClass); 29 | } 30 | }, 31 | enable = function () { 32 | applyStickNav(); 33 | win.on('resize', applyStickNav); 34 | }, 35 | init = function () { 36 | navBar = jquery('nav.wy-nav-side:first'); 37 | win = jquery(window); 38 | }; 39 | jquery(init); 40 | return { 41 | enable : enable 42 | }; 43 | }()); 44 | return { 45 | StickyNav : stickyNav 46 | }; 47 | }($)); 48 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/admin.sortable.html: -------------------------------------------------------------------------------- 1 | 55 | -------------------------------------------------------------------------------- /docs/django-cms.rst: -------------------------------------------------------------------------------- 1 | Django-CMS Integration 2 | ====================== 3 | 4 | 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:: 5 | 6 | # example plugin 7 | from cms.plugin_base import CMSPluginBase 8 | 9 | class CMSCarouselPlugin(CMSPluginBase): 10 | admin_preview = False 11 | change_form_template = 'cms/sortable-stacked-inline-change-form.html' 12 | inlines = [SlideInline] 13 | model = Carousel 14 | name = _('Carousel') 15 | render_template = 'carousels/carousel.html' 16 | 17 | def render(self, context, instance, placeholder): 18 | context.update({ 19 | 'carousel': instance, 20 | 'placeholder': placeholder 21 | }) 22 | return context 23 | 24 | plugin_pool.register_plugin(CMSCarouselPlugin) 25 | 26 | The contents of sortable-stacked-inline-change-form.html at a minimum need to extend the extrahead block with:: 27 | 28 | {% extends "admin/cms/page/plugin_change_form.html" %} 29 | {% load static from staticfiles %} 30 | 31 | {% block extrahead %} 32 | {{ block.super }} 33 | 34 | 35 | 36 | 37 | 38 | {% endblock extrahead %} 39 | 40 | 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:: 41 | 42 | 43 | 44 | with:: 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/django-cms.txt: -------------------------------------------------------------------------------- 1 | Django-CMS Integration 2 | ====================== 3 | 4 | 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:: 5 | 6 | # example plugin 7 | from cms.plugin_base import CMSPluginBase 8 | 9 | class CMSCarouselPlugin(CMSPluginBase): 10 | admin_preview = False 11 | change_form_template = 'cms/sortable-stacked-inline-change-form.html' 12 | inlines = [SlideInline] 13 | model = Carousel 14 | name = _('Carousel') 15 | render_template = 'carousels/carousel.html' 16 | 17 | def render(self, context, instance, placeholder): 18 | context.update({ 19 | 'carousel': instance, 20 | 'placeholder': placeholder 21 | }) 22 | return context 23 | 24 | plugin_pool.register_plugin(CMSCarouselPlugin) 25 | 26 | The contents of sortable-stacked-inline-change-form.html at a minimum need to extend the extrahead block with:: 27 | 28 | {% extends "admin/cms/page/plugin_change_form.html" %} 29 | {% load static from staticfiles %} 30 | 31 | {% block extrahead %} 32 | {{ block.super }} 33 | 34 | 35 | 36 | 37 | 38 | {% endblock extrahead %} 39 | 40 | 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:: 41 | 42 | 43 | 44 | with:: 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/edit_inline/stacked.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls static %} 2 |
    6 |
    7 |

    {{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

    8 | {{ inline_admin_formset.formset.management_form }} 9 | {{ inline_admin_formset.formset.non_form_errors }} 10 | 11 | {% for inline_admin_form in inline_admin_formset %}
    12 |

    13 | {% if inline_admin_form.original %} 14 | {% with initial_forms_count=inline_admin_formset.formset.management_form.INITIAL_FORMS.value %} 15 | 16 | {% endwith %} 17 | {% endif %} 18 | {{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% trans "Change" %}{% endif %} 19 | {% else %}#{{ forloop.counter }}{% endif %} 20 | {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} 21 | {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} 22 |

    23 | {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} 24 | {% for fieldset in inline_admin_form %} 25 | {% include "admin/includes/fieldset.html" %} 26 | {% endfor %} 27 | {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} 28 | {{ inline_admin_form.fk_field.field }} 29 | {% if inline_admin_form.original %} 30 | 31 | {% endif %} 32 |
    {% endfor %} 33 |
    34 |
    35 | -------------------------------------------------------------------------------- /docs/_build/html/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:"\f02d"}.icon-book:before{content:"\f02d"}.fa-caret-down:before{content:"\f0d7"}.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}} 2 | -------------------------------------------------------------------------------- /adminsortable/templatetags/django_template_additions.py: -------------------------------------------------------------------------------- 1 | from itertools import groupby 2 | 3 | import django 4 | from django import template 5 | 6 | register = template.Library() 7 | 8 | 9 | class DynamicRegroupNode(template.Node): 10 | """ 11 | Extends Django's regroup tag to accept a variable instead of a string literal 12 | for the property you want to regroup on 13 | """ 14 | 15 | def __init__(self, target, parser, expression, var_name): 16 | self.target = target 17 | self.expression = template.Variable(expression) 18 | self.var_name = var_name 19 | self.parser = parser 20 | 21 | def render(self, context): 22 | obj_list = self.target.resolve(context, True) 23 | if obj_list is None: 24 | # target variable wasn't found in context; fail silently. 25 | context[self.var_name] = [] 26 | return '' 27 | # List of dictionaries in the format: 28 | # {'grouper': 'key', 'list': [list of contents]}. 29 | 30 | #Try to resolve the filter expression from the template context. 31 | #If the variable doesn't exist, accept the value that passed to the 32 | #template tag and convert it to a string 33 | try: 34 | exp = self.expression.resolve(context) 35 | except template.VariableDoesNotExist: 36 | exp = str(self.expression) 37 | 38 | filter_exp = self.parser.compile_filter(exp) 39 | 40 | context[self.var_name] = [ 41 | {'grouper': key, 'list': list(val)} 42 | for key, val in 43 | groupby(obj_list, lambda v, f=filter_exp.resolve: f(v, True)) 44 | ] 45 | 46 | return '' 47 | 48 | 49 | @register.tag 50 | def dynamic_regroup(parser, token): 51 | """ 52 | Django expects the value of `expression` to be an attribute available on 53 | your objects. The value you pass to the template tag gets converted into a 54 | FilterExpression object from the literal. 55 | 56 | Sometimes we need the attribute to group on to be dynamic. So, instead 57 | of converting the value to a FilterExpression here, we're going to pass the 58 | value as-is and convert it in the Node. 59 | """ 60 | firstbits = token.contents.split(None, 3) 61 | if len(firstbits) != 4: 62 | raise template.TemplateSyntaxError("'regroup' tag takes five arguments") 63 | target = parser.compile_filter(firstbits[1]) 64 | if firstbits[2] != 'by': 65 | raise template.TemplateSyntaxError( 66 | "second argument to 'regroup' tag must be 'by'") 67 | lastbits_reversed = firstbits[3][::-1].split(None, 2) 68 | if lastbits_reversed[1][::-1] != 'as': 69 | raise template.TemplateSyntaxError( 70 | "next-to-last argument to 'regroup' tag must be 'as'") 71 | 72 | expression = lastbits_reversed[2][::-1] 73 | var_name = lastbits_reversed[0][::-1] 74 | #We also need to hand the parser to the node in order to convert the value 75 | #for `expression` to a FilterExpression. 76 | return DynamicRegroupNode(target, parser, expression, var_name) 77 | 78 | 79 | @register.simple_tag 80 | def get_django_version(): 81 | version = django.VERSION 82 | return {'major': version[0], 'minor': version[1]} 83 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/edit_inline/admin.sortable.stacked.inlines.html: -------------------------------------------------------------------------------- 1 | 79 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/edit_inline/admin.sortable.tabular.inlines.html: -------------------------------------------------------------------------------- 1 | 78 | -------------------------------------------------------------------------------- /adminsortable/locale/pt_BR/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | #, fuzzy 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: adminsortable\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2013-05-20 16:24+0200\n" 7 | "PO-Revision-Date: 2013-02-13 02:17+0200\n" 8 | "Last-Translator: Gladson Simplicio Brito \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | 13 | #: templates/adminsortable/change_form.html:32 14 | msgid "" 15 | "There are unsaved changes on this page. Please save your changes before " 16 | "reordering." 17 | msgstr "" 18 | "Há alterações não salvas nesta página. Por favor, salve as alterações antes de " 19 | "reordenar." 20 | 21 | #: templates/adminsortable/change_list.html:19 22 | #, python-format 23 | msgid "Drag and drop %(model)s to change display order" 24 | msgstr "Arraste e solte %(model)s para mudar a ordem de exibição" 25 | 26 | #: templates/adminsortable/change_list.html:19 27 | msgid "Django site admin" 28 | msgstr "" 29 | 30 | #: templates/adminsortable/change_list.html:24 31 | msgid "Home" 32 | msgstr "" 33 | 34 | #: templates/adminsortable/change_list.html:31 35 | msgid "Reorder" 36 | msgstr "Reordenar" 37 | 38 | #: templates/adminsortable/change_list.html:38 39 | #, python-format 40 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 41 | msgstr "Arraste e solte %(sort_type)s %(model)s para alterar a ordem." 42 | 43 | #: templates/adminsortable/change_list.html:40 44 | #, python-format 45 | msgid "Drag and drop %(model)s to change their order." 46 | msgstr "Arraste e solte %(model)s para alterar a ordem." 47 | 48 | #: templates/adminsortable/change_list.html:45 49 | #, python-format 50 | msgid "" 51 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 52 | "their order." 53 | msgstr "" 54 | "Você também pode arrastar e soltar %(sortable_by_class_display_name)s " 55 | "para alterar a ordem." 56 | 57 | #: templates/adminsortable/change_list.html:56 58 | #, python-format 59 | msgid "Return to %(model)s" 60 | msgstr "Retornar para %(model)s" 61 | 62 | #: templates/adminsortable/change_list_with_sort_link.html:6 63 | msgid "Change Order" 64 | msgstr "Alterar ordem" 65 | 66 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:4 67 | #: templates/adminsortable/edit_inline/stacked.html:3 68 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:7 69 | #: templates/adminsortable/edit_inline/tabular.html:6 70 | msgid "drag and drop to change order" 71 | msgstr "arrastar e soltar para alterar a ordem de" 72 | 73 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:10 74 | #: templates/adminsortable/edit_inline/stacked.html:9 75 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:30 76 | #: templates/adminsortable/edit_inline/tabular.html:30 77 | msgid "View on site" 78 | msgstr "Ver no site" 79 | 80 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:71 81 | #: templates/adminsortable/edit_inline/stacked.html:30 82 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:118 83 | #: templates/adminsortable/edit_inline/tabular.html:78 84 | #, python-format 85 | msgid "Add another %(verbose_name)s" 86 | msgstr "Adicione mais %(verbose_name)s" 87 | 88 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:74 89 | #: templates/adminsortable/edit_inline/stacked.html:29 90 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:121 91 | #: templates/adminsortable/edit_inline/tabular.html:79 92 | msgid "Remove" 93 | msgstr "Remover" 94 | 95 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:16 96 | #: templates/adminsortable/edit_inline/tabular.html:17 97 | msgid "Delete?" 98 | msgstr "Deletar?" -------------------------------------------------------------------------------- /adminsortable/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: Adminsortable 1.6.2\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2013-12-03 10:36+0100\n" 11 | "PO-Revision-Date: 2013-12-03 10:37+0100\n" 12 | "Last-Translator: Moritz Pfeiffer \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | "X-Generator: Poedit 1.5.7\n" 19 | 20 | #: templates/adminsortable/change_form.html:32 21 | msgid "" 22 | "There are unsaved changes on this page. Please save your changes before " 23 | "reordering." 24 | msgstr "" 25 | "Bitte speichern Sie zuerst die Änderungen auf dieser Seite bevor Sie die " 26 | "Reihenfolge ändern." 27 | 28 | #: templates/adminsortable/change_list.html:19 29 | #, python-format 30 | msgid "Drag and drop %(model)s to change display order" 31 | msgstr "Drag and drop %(model)s um die Reihenfolge zu ändern" 32 | 33 | #: templates/adminsortable/change_list.html:19 34 | msgid "Django site admin" 35 | msgstr "" 36 | 37 | #: templates/adminsortable/change_list.html:24 38 | msgid "Home" 39 | msgstr "" 40 | 41 | #: templates/adminsortable/change_list.html:31 42 | msgid "Reorder" 43 | msgstr "Reihenfolge ändern" 44 | 45 | #: templates/adminsortable/change_list.html:38 46 | #, python-format 47 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 48 | msgstr "Drag and drop %(sort_type)s %(model)s um die Reihenfolge zu ändern." 49 | 50 | #: templates/adminsortable/change_list.html:40 51 | #, python-format 52 | msgid "Drag and drop %(model)s to change their order." 53 | msgstr "Drag and drop %(model)s um ihre Reihenfolge zu ändern." 54 | 55 | #: templates/adminsortable/change_list.html:45 56 | #, python-format 57 | msgid "" 58 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 59 | "their order." 60 | msgstr "" 61 | "Sie können per drag and drop die Reihenfolge von " 62 | "%(sortable_by_class_display_name)s ändern." 63 | 64 | #: templates/adminsortable/change_list.html:56 65 | #, python-format 66 | msgid "Return to %(model)s" 67 | msgstr "Zurück zu %(model)s" 68 | 69 | #: templates/adminsortable/change_list_with_sort_link.html:6 70 | msgid "Change Order" 71 | msgstr "Reihenfolge ändern" 72 | 73 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:4 74 | #: templates/adminsortable/edit_inline/stacked.html:3 75 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:7 76 | #: templates/adminsortable/edit_inline/tabular.html:6 77 | msgid "drag and drop to change order" 78 | msgstr "drag and drop um die Reihenfolge zu ändern" 79 | 80 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:10 81 | #: templates/adminsortable/edit_inline/stacked.html:9 82 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:30 83 | #: templates/adminsortable/edit_inline/tabular.html:30 84 | msgid "View on site" 85 | msgstr "" 86 | 87 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:71 88 | #: templates/adminsortable/edit_inline/stacked.html:30 89 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:118 90 | #: templates/adminsortable/edit_inline/tabular.html:78 91 | #, python-format 92 | msgid "Add another %(verbose_name)s" 93 | msgstr "" 94 | 95 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:74 96 | #: templates/adminsortable/edit_inline/stacked.html:29 97 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:121 98 | #: templates/adminsortable/edit_inline/tabular.html:79 99 | msgid "Remove" 100 | msgstr "Entfernen" 101 | 102 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:16 103 | #: templates/adminsortable/edit_inline/tabular.html:17 104 | msgid "Delete?" 105 | msgstr "Löschen?" 106 | -------------------------------------------------------------------------------- /docs/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 16 | .highlight .go { color: #333333 } /* Generic.Output */ 17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #902000 } /* Keyword.Type */ 27 | .highlight .m { color: #208050 } /* Literal.Number */ 28 | .highlight .s { color: #4070a0 } /* Literal.String */ 29 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 30 | .highlight .nb { color: #007020 } /* Name.Builtin */ 31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #60add5 } /* Name.Constant */ 33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #007020 } /* Name.Exception */ 36 | .highlight .nf { color: #06287e } /* Name.Function */ 37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /adminsortable/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-04-08 00:54-0600\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: templates/adminsortable/change_form.html:32 22 | msgid "" 23 | "There are unsaved changes on this page. Please save your changes before " 24 | "reordering." 25 | msgstr "Hay cambios sin guardar en esta página. Guarda los cambios antes de reordenar." 26 | 27 | #: templates/adminsortable/change_list.html:19 28 | #, python-format 29 | msgid "Drag and drop %(model)s to change display order" 30 | msgstr "Arrastrar y soltar %(model)s para cambiar el orden en que se muestra" 31 | 32 | #: templates/adminsortable/change_list.html:19 33 | msgid "Django site admin" 34 | msgstr "Sitio de administración de Django" 35 | 36 | #: templates/adminsortable/change_list.html:24 37 | msgid "Home" 38 | msgstr "Inicio" 39 | 40 | #: templates/adminsortable/change_list.html:31 41 | msgid "Reorder" 42 | msgstr "Reordenar" 43 | 44 | #: templates/adminsortable/change_list.html:38 45 | #, python-format 46 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 47 | msgstr "Arrastrar y soltar %(model)s %(sort_type)s para cambiar su orden." 48 | 49 | #: templates/adminsortable/change_list.html:40 50 | #, python-format 51 | msgid "Drag and drop %(model)s to change their order." 52 | msgstr "Arrastrar y soltar %(model)s para cambiar su orden" 53 | 54 | #: templates/adminsortable/change_list.html:45 55 | #, python-format 56 | msgid "" 57 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 58 | "their order." 59 | msgstr "Puedes arrastrar y soltar %(sortable_by_class_display_name)s para cambiar su orden." 60 | 61 | #: templates/adminsortable/change_list.html:56 62 | #, python-format 63 | msgid "Return to %(model)s" 64 | msgstr "Regresar a %(model)s" 65 | 66 | #: templates/adminsortable/change_list_with_sort_link.html:7 67 | msgid "Change Order of" 68 | msgstr "Cambiar el orden de" 69 | 70 | #: templates/adminsortable/change_list_with_sort_link.html:11 71 | msgid "Change Order" 72 | msgstr "Cambiar orden" 73 | 74 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:4 75 | #: templates/adminsortable/edit_inline/stacked.html:3 76 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:7 77 | #: templates/adminsortable/edit_inline/tabular.html:6 78 | msgid "drag and drop to change order" 79 | msgstr "arrastrar y soltar para cambiar el orden" 80 | 81 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:10 82 | #: templates/adminsortable/edit_inline/stacked.html:9 83 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:30 84 | #: templates/adminsortable/edit_inline/tabular.html:30 85 | msgid "View on site" 86 | msgstr "Ver en el sitio" 87 | 88 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:71 89 | #: templates/adminsortable/edit_inline/stacked.html:30 90 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:118 91 | #: templates/adminsortable/edit_inline/tabular.html:78 92 | #, python-format 93 | msgid "Add another %(verbose_name)s" 94 | msgstr "Añadir otro %(verbose_name)s" 95 | 96 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:74 97 | #: templates/adminsortable/edit_inline/stacked.html:29 98 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:121 99 | #: templates/adminsortable/edit_inline/tabular.html:79 100 | msgid "Remove" 101 | msgstr "Eliminar" 102 | 103 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:16 104 | #: templates/adminsortable/edit_inline/tabular.html:17 105 | msgid "Delete?" 106 | msgstr "¿Eliminar?" 107 | -------------------------------------------------------------------------------- /adminsortable/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-05-20 01:01-0500\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" 20 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" 21 | 22 | #: templates/adminsortable/change_form.html:32 23 | msgid "" 24 | "There are unsaved changes on this page. Please save your changes before " 25 | "reordering." 26 | msgstr "Есть несохраненные изменения на этой странице. Пожалуйста, сохраните изменения перед сортировкой" 27 | 28 | #: templates/adminsortable/change_list.html:19 29 | #, python-format 30 | msgid "Drag and drop %(model)s to change display order" 31 | msgstr "Перетащите %(model)s для изменения порядка вывода" 32 | 33 | #: templates/adminsortable/change_list.html:19 34 | msgid "Django site admin" 35 | msgstr "" 36 | 37 | #: templates/adminsortable/change_list.html:24 38 | msgid "Home" 39 | msgstr "" 40 | 41 | #: templates/adminsortable/change_list.html:31 42 | msgid "Reorder" 43 | msgstr "Сортировать" 44 | 45 | #: templates/adminsortable/change_list.html:38 46 | #, python-format 47 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 48 | msgstr "Перетащите %(sort_type)s %(model)s для изменения их порядка вывода." 49 | 50 | #: templates/adminsortable/change_list.html:40 51 | #, python-format 52 | msgid "Drag and drop %(model)s to change their order." 53 | msgstr "Перетащите %(model)s для изменения их порядка вывода." 54 | 55 | #: templates/adminsortable/change_list.html:45 56 | #, python-format 57 | msgid "" 58 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 59 | "their order." 60 | msgstr "" 61 | "Вы также можете перетащить %(sortable_by_class_display_name)s для изменения их порядка вывода." 62 | #: templates/adminsortable/change_list.html:56 63 | #, python-format 64 | msgid "Return to %(model)s" 65 | msgstr "Вернуться к %(model)s" 66 | 67 | #: templates/adminsortable/change_list_with_sort_link.html:7 68 | msgid "Change Order of" 69 | msgstr "Изменение порядка для " 70 | 71 | #: templates/adminsortable/change_list_with_sort_link.html:11 72 | msgid "Change Order" 73 | msgstr "Изменить порядок вывода" 74 | 75 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:4 76 | #: templates/adminsortable/edit_inline/stacked.html:3 77 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:7 78 | #: templates/adminsortable/edit_inline/tabular.html:6 79 | msgid "drag and drop to change order" 80 | msgstr "Перетащите для изменения порядка вывода." 81 | 82 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:10 83 | #: templates/adminsortable/edit_inline/stacked.html:9 84 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:30 85 | #: templates/adminsortable/edit_inline/tabular.html:30 86 | msgid "View on site" 87 | msgstr "Посмотреть на сайте" 88 | 89 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:71 90 | #: templates/adminsortable/edit_inline/stacked.html:30 91 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:118 92 | #: templates/adminsortable/edit_inline/tabular.html:78 93 | #, python-format 94 | msgid "Add another %(verbose_name)s" 95 | msgstr "Добавить еще %(verbose_name)s" 96 | 97 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:74 98 | #: templates/adminsortable/edit_inline/stacked.html:29 99 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:121 100 | #: templates/adminsortable/edit_inline/tabular.html:79 101 | msgid "Remove" 102 | msgstr "Убрать" 103 | 104 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:16 105 | #: templates/adminsortable/edit_inline/tabular.html:17 106 | msgid "Delete?" 107 | msgstr "Удалить" 108 | -------------------------------------------------------------------------------- /adminsortable/locale/pl/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: django-adminsortable 1.8.1\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2015-03-30 18:37+0200\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: Tomasz Gabrysiak \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " 20 | "|| n%100>=20) ? 1 : 2);\n" 21 | 22 | #: templates/adminsortable/change_form.html:32 23 | msgid "" 24 | "There are unsaved changes on this page. Please save your changes before " 25 | "reordering." 26 | msgstr "Na stronie są niezapisane zmiany. Proszę zapisać zmiany przed " 27 | "zmianą kolejności." 28 | 29 | #: templates/adminsortable/change_list.html:19 30 | #, python-format 31 | msgid "Drag and drop %(model)s to change display order" 32 | msgstr "Przeciągnij i upuść %(model)s aby zmienić kolejność wyświetlania" 33 | 34 | #: templates/adminsortable/change_list.html:19 35 | msgid "Django site admin" 36 | msgstr "" 37 | 38 | #: templates/adminsortable/change_list.html:24 39 | msgid "Home" 40 | msgstr "" 41 | 42 | #: templates/adminsortable/change_list.html:31 43 | msgid "Reorder" 44 | msgstr "Zmień kolejność" 45 | 46 | #: templates/adminsortable/change_list.html:38 47 | #, python-format 48 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 49 | msgstr "Przeciągnij i upuść %(sort_type)s %(model)s aby zmienić kolejność." 50 | 51 | #: templates/adminsortable/change_list.html:40 52 | #, python-format 53 | msgid "Drag and drop %(model)s to change their order." 54 | msgstr "Przeciągnij i upuść %(model)s aby zmienić ich kolejność." 55 | 56 | #: templates/adminsortable/change_list.html:45 57 | #, python-format 58 | msgid "" 59 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 60 | "their order." 61 | msgstr "Możesz też przeciągnąć i upuścić %(sortable_by_class_display_name)s aby zmienić " 62 | "ich kolejność" 63 | 64 | #: templates/adminsortable/change_list.html:56 65 | #, python-format 66 | msgid "Return to %(model)s" 67 | msgstr "Wróć do %(model)s" 68 | 69 | #: templates/adminsortable/change_list_with_sort_link.html:7 70 | msgid "Change Order of" 71 | msgstr "Zmień kolejność" 72 | 73 | #: templates/adminsortable/change_list_with_sort_link.html:11 74 | msgid "Change Order" 75 | msgstr "Zmień kolejność" 76 | 77 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:4 78 | #: templates/adminsortable/edit_inline/stacked.html:3 79 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:7 80 | #: templates/adminsortable/edit_inline/tabular.html:6 81 | msgid "drag and drop to change order" 82 | msgstr "przeciągnij i upuść aby zmienić kolejność" 83 | 84 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:10 85 | #: templates/adminsortable/edit_inline/stacked.html:9 86 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:30 87 | #: templates/adminsortable/edit_inline/tabular.html:30 88 | msgid "View on site" 89 | msgstr "Zobacz na stronie" 90 | 91 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:71 92 | #: templates/adminsortable/edit_inline/stacked.html:30 93 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:118 94 | #: templates/adminsortable/edit_inline/tabular.html:78 95 | #, python-format 96 | msgid "Add another %(verbose_name)s" 97 | msgstr "Dodaj kolejne %(verbose_name)s" 98 | 99 | #: templates/adminsortable/edit_inline/stacked-1.5.x.html:74 100 | #: templates/adminsortable/edit_inline/stacked.html:29 101 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:121 102 | #: templates/adminsortable/edit_inline/tabular.html:79 103 | msgid "Remove" 104 | msgstr "Usuń" 105 | 106 | #: templates/adminsortable/edit_inline/tabular-1.5.x.html:16 107 | #: templates/adminsortable/edit_inline/tabular.html:17 108 | msgid "Delete?" 109 | msgstr "Usunąć?" 110 | -------------------------------------------------------------------------------- /adminsortable/locale/uk/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2019-06-21 23:37+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != " 20 | "11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % " 21 | "100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || " 22 | "(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" 23 | 24 | #: templates/adminsortable/change_form.html:33 25 | msgid "" 26 | "There are unsaved changes on this page. Please save your changes before " 27 | "reordering." 28 | msgstr "На цій сторінці є незбережені зміни. Будь ласка, збережіть ваші зміни перед зміною порядку." 29 | 30 | #: templates/adminsortable/change_list.html:53 31 | #, python-format 32 | msgid "Drag and drop %(model)s to change display order" 33 | msgstr "Перетягніть %(model)s, щоб змінити порядок відображення" 34 | 35 | #: templates/adminsortable/change_list.html:53 36 | msgid "Django site admin" 37 | msgstr "Django адміністрування" 38 | 39 | #: templates/adminsortable/change_list.html:59 40 | msgid "Home" 41 | msgstr "Домівка" 42 | 43 | #: templates/adminsortable/change_list.html:70 44 | msgid "Reorder" 45 | msgstr "Зміна порядку" 46 | 47 | #: templates/adminsortable/change_list.html:78 48 | #, python-format 49 | msgid "Drag and drop %(sort_type)s %(model)s to change their order." 50 | msgstr "Перетягніть %(sort_type)s %(model)s, щоб змінити їх порядок" 51 | 52 | #: templates/adminsortable/change_list.html:80 53 | #, python-format 54 | msgid "Drag and drop %(model)s to change their order." 55 | msgstr "Перетягніть %(model)s, щоб змінити їх порядок" 56 | 57 | #: templates/adminsortable/change_list.html:85 58 | #, python-format 59 | msgid "" 60 | "You may also drag and drop %(sortable_by_class_display_name)s to change " 61 | "their order." 62 | msgstr "Ви також можете перетягнути %(sortable_by_class_display_name)s, щоб змінити їх порядок" 63 | 64 | #: templates/adminsortable/change_list.html:98 65 | #, python-format 66 | msgid "Return to %(model)s" 67 | msgstr "Повернутись до %(model)s" 68 | 69 | #: templates/adminsortable/change_list_with_sort_link.html:24 70 | msgid "Change Order of" 71 | msgstr "Змінити порядок" 72 | 73 | #: templates/adminsortable/change_list_with_sort_link.html:29 74 | msgid "Change Order" 75 | msgstr "Змінити порядок" 76 | 77 | #: templates/adminsortable/edit_inline/stacked-1.10.x.html:12 78 | #: templates/adminsortable/edit_inline/stacked.html:15 79 | #: templates/adminsortable/edit_inline/tabular-1.10.x.html:34 80 | #: templates/adminsortable/edit_inline/tabular.html:35 81 | msgid "Change" 82 | msgstr "Змінити" 83 | 84 | #: templates/adminsortable/edit_inline/stacked-1.10.x.html:14 85 | #: templates/adminsortable/edit_inline/stacked.html:17 86 | #: templates/adminsortable/edit_inline/tabular-1.10.x.html:36 87 | #: templates/adminsortable/edit_inline/tabular.html:37 88 | msgid "View on site" 89 | msgstr "Дивитися на сайті" 90 | 91 | #: templates/adminsortable/edit_inline/stacked.html:4 92 | #: templates/adminsortable/edit_inline/tabular.html:7 93 | msgid "drag and drop to change order" 94 | msgstr "перетягніть, щоб змінити порядок" 95 | 96 | #: templates/adminsortable/edit_inline/stacked.html:37 97 | #: templates/adminsortable/edit_inline/tabular.html:86 98 | msgid "Remove" 99 | msgstr "Видалити" 100 | 101 | #: templates/adminsortable/edit_inline/stacked.html:38 102 | #: templates/adminsortable/edit_inline/tabular.html:85 103 | #, python-format 104 | msgid "Add another %(verbose_name)s" 105 | msgstr "Додати ще %(verbose_name)s" 106 | 107 | #: templates/adminsortable/edit_inline/tabular-1.10.x.html:20 108 | #: templates/adminsortable/edit_inline/tabular.html:18 109 | msgid "Delete?" 110 | msgstr "Видалити?" 111 | -------------------------------------------------------------------------------- /sample_project/samples/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from adminsortable.admin import (SortableAdmin, SortableTabularInline, 4 | SortableStackedInline, SortableGenericStackedInline, 5 | NonSortableParentAdmin) 6 | from adminsortable.utils import get_is_sortable 7 | from .models import (Category, Widget, Project, Credit, Note, GenericNote, 8 | Component, Person, NonSortableCategory, SortableCategoryWidget, 9 | SortableNonInlineCategory, NonSortableCredit, NonSortableNote, 10 | CustomWidget, CustomWidgetComponent, BackwardCompatibleWidget) 11 | 12 | 13 | admin.site.register(Category, SortableAdmin) 14 | 15 | 16 | class ComponentInline(SortableStackedInline): 17 | # fieldsets = ( 18 | # ('foo', { 19 | # 'classes': ('collapse',), 20 | # 'fields': ('title',) 21 | # }), 22 | # ('', { 23 | # 'classes': ('collapse',), 24 | # 'fields': ('widget',) 25 | # }), 26 | # ) 27 | model = Component 28 | 29 | def get_queryset(self, request): 30 | qs = super(ComponentInline, self).get_queryset( 31 | request).exclude(title__icontains='2') 32 | if get_is_sortable(qs): 33 | self.model.is_sortable = True 34 | else: 35 | self.model.is_sortable = False 36 | return qs 37 | 38 | 39 | class WidgetAdmin(SortableAdmin): 40 | def get_queryset(self, request): 41 | """ 42 | A simple example demonstrating that adminsortable works even in 43 | situations where you need to filter the queryset in admin. Here, 44 | we are just filtering out `widget` instances with an pk higher 45 | than 3 46 | """ 47 | qs = super(WidgetAdmin, self).get_queryset(request) 48 | return qs.filter(id__lte=3) 49 | 50 | inlines = [ComponentInline] 51 | 52 | admin.site.register(Widget, WidgetAdmin) 53 | 54 | 55 | class CreditAdmin(SortableAdmin): 56 | raw_id_fields = ('project',) 57 | 58 | admin.site.register(Credit, CreditAdmin) 59 | 60 | 61 | class CreditInline(SortableTabularInline): 62 | model = Credit 63 | extra = 1 64 | 65 | 66 | class NoteInline(SortableStackedInline): 67 | model = Note 68 | extra = 2 69 | 70 | def after_sorting(self): 71 | print('I happened after sorting') 72 | 73 | 74 | class GenericNoteInline(SortableGenericStackedInline): 75 | model = GenericNote 76 | extra = 0 77 | 78 | 79 | class NonSortableCreditInline(admin.TabularInline): 80 | model = NonSortableCredit 81 | extra = 1 82 | 83 | 84 | class NonSortableNoteInline(admin.StackedInline): 85 | model = NonSortableNote 86 | extra = 0 87 | 88 | 89 | class ProjectAdmin(SortableAdmin): 90 | inlines = [ 91 | CreditInline, NoteInline, GenericNoteInline, 92 | NonSortableCreditInline, NonSortableNoteInline 93 | ] 94 | list_display = ['__str__', 'category', 'isApproved',] 95 | list_filter = ('category__title', 'isApproved',) 96 | after_sorting_js_callback_name = 'afterSortCallback' 97 | search_fields = ['title'] 98 | sortable_change_list_template = 'adminsortable/custom_change_list.html' 99 | sortable_change_form_template = 'adminsortable/custom_change_form.html' 100 | 101 | def after_sorting(self): 102 | print('I happened after sorting') 103 | 104 | admin.site.register(Project, ProjectAdmin) 105 | 106 | 107 | class PersonAdmin(SortableAdmin): 108 | list_display = ['__str__', 'is_board_member'] 109 | 110 | admin.site.register(Person, PersonAdmin) 111 | 112 | 113 | class SortableCategoryWidgetInline(SortableStackedInline): 114 | model = SortableCategoryWidget 115 | extra = 0 116 | 117 | 118 | class NonSortableCategoryAdmin(NonSortableParentAdmin): 119 | inlines = [SortableCategoryWidgetInline] 120 | 121 | admin.site.register(NonSortableCategory, NonSortableCategoryAdmin) 122 | 123 | 124 | class CustomWidgetComponentInline(SortableStackedInline): 125 | model = CustomWidgetComponent 126 | extra = 0 127 | 128 | 129 | class CustomWidgetAdmin(SortableAdmin): 130 | inlines = [CustomWidgetComponentInline] 131 | 132 | 133 | admin.site.register(SortableNonInlineCategory, SortableAdmin) 134 | admin.site.register(CustomWidget, CustomWidgetAdmin) 135 | admin.site.register(BackwardCompatibleWidget, SortableAdmin) 136 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/change_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n admin_urls static admin_list %} 3 | 4 | {% block extrastyle %} 5 | {{ block.super }} 6 | 7 | {% if cl.formset %} 8 | 9 | {% endif %} 10 | {% if cl.formset or action_form %} 11 | 12 | {% endif %} 13 | {{ media.css }} 14 | {% if not actions_on_top and not actions_on_bottom %} 15 | 18 | {% endif %} 19 | 20 | 21 | {% endblock %} 22 | 23 | {% block extrahead %} 24 | 25 | 26 | {{ block.super }} 27 | {{ media.js }} 28 | 29 | 30 | {% include 'adminsortable/csrf/jquery.django-csrf.html' with csrf_cookie_name=csrf_cookie_name %} 31 | {% include 'adminsortable/admin.sortable.html' with after_sorting_js_callback_name=after_sorting_js_callback_name %} 32 | 33 | 49 | {% endblock %} 50 | 51 | {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %} 52 | 53 | {% block title %}{% blocktrans with opts.verbose_name_plural|capfirst as model %}Drag and drop {{ model }} to change display order{% endblocktrans %} | {% trans 'Django site admin' %}{% endblock %} 54 | 55 | {% if not is_popup %} 56 | {% block breadcrumbs %} 57 | 72 | {% endblock %} 73 | {% endif %} 74 | 75 | {% block content_title %} 76 |

    77 | {% if sort_type %} 78 | {% blocktrans with opts.verbose_name_plural|capfirst as model %}Drag and drop {{ sort_type }} {{ model }} to change their order.{% endblocktrans %} 79 | {% else %} 80 | {% blocktrans with opts.verbose_name_plural|capfirst as model %}Drag and drop {{ model }} to change their order.{% endblocktrans %} 81 | {% endif %} 82 |

    83 | {% if sortable_by_class_is_sortable %} 84 |

    85 | {% blocktrans %}You may also drag and drop {{ sortable_by_class_display_name }} to change their order.{% endblocktrans %} 86 |

    87 | {% endif %} 88 | {% endblock %} 89 | 90 | {% block coltype %}flex{% endblock %} 91 | 92 | {% block content %} 93 |
    94 | {% block object-tools %} 95 | 102 | {% endblock %} 103 | {% if objects %} 104 |
    105 | {% if group_expression %} 106 | {% include "adminsortable/shared/nested_objects.html" %} 107 | {% else %} 108 | {% include "adminsortable/shared/objects.html" %} 109 | {% endif %} 110 |
    111 | {% endif %} 112 |
    113 | {% endblock %} 114 | -------------------------------------------------------------------------------- /adminsortable/templates/adminsortable/edit_inline/tabular.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls static admin_modify django_template_additions %} 2 |
    5 | 81 |
    82 | -------------------------------------------------------------------------------- /docs/_build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({envversion:42,terms:{all:8,code:8,plugin_bas:10,follow:8,row:7,whose:4,depend:8,cmspluginbas:10,positivesmallinteg:8,under:3,introduc:[8,1,7],rel:[8,10],fals:[8,10],util:8,context_processor:[9,2],veri:8,change_form_templ:10,list:8,last_nam:8,item:1,small:8,sortablestackedinlin:8,pleas:1,fortun:10,pass:[8,2],click:5,compat:1,index:[8,1],appear:8,mysortabletabularinlin:8,abl:8,change_list:8,"new":[],"public":3,gener:8,here:[8,2],valu:8,search:1,extrahead:10,stackedinlin:8,opinion:7,chang:[8,1,4,5,10],honor:8,via:5,extra:[8,2],appli:8,modul:1,prefer:9,href:10,instal:2,unit:[6,5],register_plugin:10,from:[2,4,5,10,8,9],would:8,regist:[8,2],two:8,few:[8,9],stylesheet:10,recommend:8,taken:5,type:10,more:[8,2],sort:[],desir:2,peopl:8,get_queryset:8,site:[8,2],known:[],must:8,placehold:10,work:[8,5,10],can:[8,5,2,9],caveat:8,def:[8,10,2],quickstart:[],sortablegenericstackedinlin:8,tabular:[8,10],minimum:10,mysortablestackedinlin:8,edit_inlin:8,first_nam:8,anoth:[],cmscarouselplugin:10,instead:8,simpl:9,css:[8,9,10],updat:[1,10],product:0,after:8,befor:8,mai:[8,1,5],associ:7,feasibl:10,credenti:5,imposs:7,issu:[],inform:8,allow:[8,10],tall:8,order:[5,2],help:6,anticip:8,over:8,move:6,becaus:4,through:1,dynam:8,group:[8,1,7],thank:1,them:8,"return":[8,10,2],python:[1,5],now:2,nor:7,name:[8,10],anyth:8,edit:7,drop:[5,2],each:8,found:5,inhert:4,individu:1,realli:[6,10],contrib:8,meta:[8,2],"static":2,special:8,out:6,categori:8,rational:[],plugin_change_form:10,insid:9,migrat:8,sortabletabularinlin:8,standard:8,base:[8,1,7],dictionari:8,releas:3,render_templ:10,could:6,filter:8,pagin:7,charfield:[8,2],top:7,south:8,render:10,onc:8,independ:8,number:8,cmsplugin:10,change_form:8,alreadi:10,stabl:0,installed_app:[9,2],script:10,data:8,licens:[],sometim:8,max_length:[8,2],carousel:10,schema:8,option:[8,2],travi:6,tool:[5,2],copi:9,specifi:[8,10],entequak:1,exactli:8,serv:9,provid:8,get_is_sort:8,jqueri:10,sai:5,changelist:[2,7],ani:[8,1,5,2],have:[8,4,5,2,7],need:[8,10,2],seem:7,incompat:[8,1],equival:8,min:10,self:[8,6,2,10],note:8,also:[8,1],take:2,which:[8,7],normal:8,sorting_filt:[8,1],object:2,change_list_template_extend:8,why:[],don:8,request:8,doe:[4,7],sample_project:5,determin:8,left:8,text:[8,10],directli:5,current:[0,4],onli:10,componentinlin:8,locat:9,apach:3,should:2,title__icontain:8,folder:9,adminsort:[8,9,2,10],hit:8,get:[9,2],csrf:10,increas:8,is_sort:8,tbd:[],requir:8,enabl:[8,1],method:[8,9],where:[5,2],view:[8,5,2,7],set:[8,2],see:[8,5],project:[2,5,6,7,8,9],statu:[],wire:2,parent:[8,4],enumer:8,won:[8,10],between:7,"import":[8,10,2],across:7,attribut:[8,1],altern:9,kei:[6,7],javascript:[8,9,10],distinguish:7,"__unicode__":[8,2],addit:8,change_form_template_extend:8,plugin:10,howev:7,foreign:[6,7],instanc:10,context:10,login:5,load:10,simpli:2,instanti:8,height:8,assum:8,quit:9,coupl:7,due:8,compon:8,much:7,present:[8,2],"case":8,look:[8,5],properti:8,defin:[8,2],endblock:10,almost:1,non:8,myapp:8,mysortableadminclass:[8,2],suggest:8,make:[8,7],referenti:6,same:8,member:8,html:[8,10],ascend:8,difficult:8,director:8,stack:[8,10],appropri:8,thu:10,inherit:[8,2],person:8,exampl:[8,10],thi:[8,6,5,7,10],admin_preview:10,model:[5,2],latest:1,just:[10,7],previous:8,foo:8,easi:[1,10],littl:7,add:[8,1,9,2],board:8,els:8,save:8,app:[5,9],plugin_pool:10,format:[8,1],is_board_memb:8,template_context_processor:[9,2],resolv:10,staticfil:[9,10],necessari:10,either:8,page:[1,10,7],right:8,sortableadmin:[8,2],some:[8,6],sampl:[8,6],slideinlin:10,substitut:10,select:8,content:[],core:[9,2],run:5,widgetadmin:8,symlink:9,"super":[8,1,10],src:10,about:8,column:8,verbose_name_plur:8,includ:[8,10,5,9],block:10,own:10,inlin:5,within:10,automat:[8,10],orm:8,ensur:[9,2],your:[8,1,9,2],manag:[1,5],wai:[8,1,4],area:5,custom:5,start:2,inner:8,forward:8,tabularinlin:8,"function":5,properli:8,form:[8,4,5,10],tupl:[8,1],link:[8,5,2,10],tabularstackedinlin:8,line:[8,7],sortablegenerictabularinlin:8,"true":8,made:1,possibl:[8,4],"default":[8,7],displai:8,record:[5,7],below:[8,1],foreignkei:8,problem:7,booleanfield:8,creat:8,file:[5,9],pip:2,mysortableclass:[8,2],titl:[8,2],when:[5,2],field:8,other:7,test:[],you:[8,1,5,2,9],"class":[8,10,2],drag:[5,2],directori:[5,9],backward:[8,1]},objtypes:{},objnames:{},filenames:["status","index","quickstart","license","known-issues","testing","future","rationale","usage","configuration","django-cms"],titles:["Status","Welcome to Django Admin Sortable’s documentation!","Quickstart","License","Known Issue(s)","Testing","Future Plans","Rationale","Using Django Admin Sortable","Configuring Django Admin Sortable","Django-CMS Integration"],objects:{},titleterms:{overrid:8,subset:8,quickstart:2,queryset:8,indic:1,order:7,exist:8,tabl:1,what:1,welcom:1,media:9,support:1,configur:9,custom:8,content:1,version:1,futur:6,rational:7,test:5,"new":1,document:1,higher:[],sort:8,sortabl:[8,1,9],extend:8,object:8,statu:0,drag:7,templat:8,known:4,inlin:8,why:7,plugin:7,admin:[8,1,9],drop:7,django:[8,1,9,10],issu:4,integr:10,anoth:7,"static":9,model:8,licens:3,plan:6}}) -------------------------------------------------------------------------------- /docs/_build/html/_static/default.css: -------------------------------------------------------------------------------- 1 | /* 2 | * default.css_t 3 | * ~~~~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- default theme. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: sans-serif; 18 | font-size: 100%; 19 | background-color: #11303d; 20 | color: #000; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.document { 26 | background-color: #1c4e63; 27 | } 28 | 29 | div.documentwrapper { 30 | float: left; 31 | width: 100%; 32 | } 33 | 34 | div.bodywrapper { 35 | margin: 0 0 0 230px; 36 | } 37 | 38 | div.body { 39 | background-color: #ffffff; 40 | color: #000000; 41 | padding: 0 20px 30px 20px; 42 | } 43 | 44 | div.footer { 45 | color: #ffffff; 46 | width: 100%; 47 | padding: 9px 0 9px 0; 48 | text-align: center; 49 | font-size: 75%; 50 | } 51 | 52 | div.footer a { 53 | color: #ffffff; 54 | text-decoration: underline; 55 | } 56 | 57 | div.related { 58 | background-color: #133f52; 59 | line-height: 30px; 60 | color: #ffffff; 61 | } 62 | 63 | div.related a { 64 | color: #ffffff; 65 | } 66 | 67 | div.sphinxsidebar { 68 | } 69 | 70 | div.sphinxsidebar h3 { 71 | font-family: 'Trebuchet MS', sans-serif; 72 | color: #ffffff; 73 | font-size: 1.4em; 74 | font-weight: normal; 75 | margin: 0; 76 | padding: 0; 77 | } 78 | 79 | div.sphinxsidebar h3 a { 80 | color: #ffffff; 81 | } 82 | 83 | div.sphinxsidebar h4 { 84 | font-family: 'Trebuchet MS', sans-serif; 85 | color: #ffffff; 86 | font-size: 1.3em; 87 | font-weight: normal; 88 | margin: 5px 0 0 0; 89 | padding: 0; 90 | } 91 | 92 | div.sphinxsidebar p { 93 | color: #ffffff; 94 | } 95 | 96 | div.sphinxsidebar p.topless { 97 | margin: 5px 10px 10px 10px; 98 | } 99 | 100 | div.sphinxsidebar ul { 101 | margin: 10px; 102 | padding: 0; 103 | color: #ffffff; 104 | } 105 | 106 | div.sphinxsidebar a { 107 | color: #98dbcc; 108 | } 109 | 110 | div.sphinxsidebar input { 111 | border: 1px solid #98dbcc; 112 | font-family: sans-serif; 113 | font-size: 1em; 114 | } 115 | 116 | 117 | 118 | /* -- hyperlink styles ------------------------------------------------------ */ 119 | 120 | a { 121 | color: #355f7c; 122 | text-decoration: none; 123 | } 124 | 125 | a:visited { 126 | color: #355f7c; 127 | text-decoration: none; 128 | } 129 | 130 | a:hover { 131 | text-decoration: underline; 132 | } 133 | 134 | 135 | 136 | /* -- body styles ----------------------------------------------------------- */ 137 | 138 | div.body h1, 139 | div.body h2, 140 | div.body h3, 141 | div.body h4, 142 | div.body h5, 143 | div.body h6 { 144 | font-family: 'Trebuchet MS', sans-serif; 145 | background-color: #f2f2f2; 146 | font-weight: normal; 147 | color: #20435c; 148 | border-bottom: 1px solid #ccc; 149 | margin: 20px -20px 10px -20px; 150 | padding: 3px 0 3px 10px; 151 | } 152 | 153 | div.body h1 { margin-top: 0; font-size: 200%; } 154 | div.body h2 { font-size: 160%; } 155 | div.body h3 { font-size: 140%; } 156 | div.body h4 { font-size: 120%; } 157 | div.body h5 { font-size: 110%; } 158 | div.body h6 { font-size: 100%; } 159 | 160 | a.headerlink { 161 | color: #c60f0f; 162 | font-size: 0.8em; 163 | padding: 0 4px 0 4px; 164 | text-decoration: none; 165 | } 166 | 167 | a.headerlink:hover { 168 | background-color: #c60f0f; 169 | color: white; 170 | } 171 | 172 | div.body p, div.body dd, div.body li { 173 | text-align: justify; 174 | line-height: 130%; 175 | } 176 | 177 | div.admonition p.admonition-title + p { 178 | display: inline; 179 | } 180 | 181 | div.admonition p { 182 | margin-bottom: 5px; 183 | } 184 | 185 | div.admonition pre { 186 | margin-bottom: 5px; 187 | } 188 | 189 | div.admonition ul, div.admonition ol { 190 | margin-bottom: 5px; 191 | } 192 | 193 | div.note { 194 | background-color: #eee; 195 | border: 1px solid #ccc; 196 | } 197 | 198 | div.seealso { 199 | background-color: #ffc; 200 | border: 1px solid #ff6; 201 | } 202 | 203 | div.topic { 204 | background-color: #eee; 205 | } 206 | 207 | div.warning { 208 | background-color: #ffe4e4; 209 | border: 1px solid #f66; 210 | } 211 | 212 | p.admonition-title { 213 | display: inline; 214 | } 215 | 216 | p.admonition-title:after { 217 | content: ":"; 218 | } 219 | 220 | pre { 221 | padding: 5px; 222 | background-color: #eeffcc; 223 | color: #333333; 224 | line-height: 120%; 225 | border: 1px solid #ac9; 226 | border-left: none; 227 | border-right: none; 228 | } 229 | 230 | code { 231 | background-color: #ecf0f3; 232 | padding: 0 1px 0 1px; 233 | font-size: 0.95em; 234 | } 235 | 236 | th { 237 | background-color: #ede; 238 | } 239 | 240 | .warning code { 241 | background: #efc2c2; 242 | } 243 | 244 | .note code { 245 | background: #d6d6d6; 246 | } 247 | 248 | .viewcode-back { 249 | font-family: sans-serif; 250 | } 251 | 252 | div.viewcode-block:target { 253 | background-color: #f4debf; 254 | border-top: 1px solid #ac9; 255 | border-bottom: 1px solid #ac9; 256 | } 257 | 258 | div.code-block-filename { 259 | color: #efefef; 260 | background-color: #1c4e63; 261 | } -------------------------------------------------------------------------------- /docs/_build/html/_static/sidebar.js: -------------------------------------------------------------------------------- 1 | /* 2 | * sidebar.js 3 | * ~~~~~~~~~~ 4 | * 5 | * This script makes the Sphinx sidebar collapsible. 6 | * 7 | * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds 8 | * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton 9 | * used to collapse and expand the sidebar. 10 | * 11 | * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden 12 | * and the width of the sidebar and the margin-left of the document 13 | * are decreased. When the sidebar is expanded the opposite happens. 14 | * This script saves a per-browser/per-session cookie used to 15 | * remember the position of the sidebar among the pages. 16 | * Once the browser is closed the cookie is deleted and the position 17 | * reset to the default (expanded). 18 | * 19 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 20 | * :license: BSD, see LICENSE for details. 21 | * 22 | */ 23 | 24 | $(function() { 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | // global elements used by the functions. 34 | // the 'sidebarbutton' element is defined as global after its 35 | // creation, in the add_sidebar_button function 36 | var bodywrapper = $('.bodywrapper'); 37 | var sidebar = $('.sphinxsidebar'); 38 | var sidebarwrapper = $('.sphinxsidebarwrapper'); 39 | 40 | // for some reason, the document has no sidebar; do not run into errors 41 | if (!sidebar.length) return; 42 | 43 | // original margin-left of the bodywrapper and width of the sidebar 44 | // with the sidebar expanded 45 | var bw_margin_expanded = bodywrapper.css('margin-left'); 46 | var ssb_width_expanded = sidebar.width(); 47 | 48 | // margin-left of the bodywrapper and width of the sidebar 49 | // with the sidebar collapsed 50 | var bw_margin_collapsed = '.8em'; 51 | var ssb_width_collapsed = '.8em'; 52 | 53 | // colors used by the current theme 54 | var dark_color = $('.related').css('background-color'); 55 | var light_color = $('.document').css('background-color'); 56 | 57 | function sidebar_is_collapsed() { 58 | return sidebarwrapper.is(':not(:visible)'); 59 | } 60 | 61 | function toggle_sidebar() { 62 | if (sidebar_is_collapsed()) 63 | expand_sidebar(); 64 | else 65 | collapse_sidebar(); 66 | } 67 | 68 | function collapse_sidebar() { 69 | sidebarwrapper.hide(); 70 | sidebar.css('width', ssb_width_collapsed); 71 | bodywrapper.css('margin-left', bw_margin_collapsed); 72 | sidebarbutton.css({ 73 | 'margin-left': '0', 74 | 'height': bodywrapper.height() 75 | }); 76 | sidebarbutton.find('span').text('»'); 77 | sidebarbutton.attr('title', _('Expand sidebar')); 78 | document.cookie = 'sidebar=collapsed'; 79 | } 80 | 81 | function expand_sidebar() { 82 | bodywrapper.css('margin-left', bw_margin_expanded); 83 | sidebar.css('width', ssb_width_expanded); 84 | sidebarwrapper.show(); 85 | sidebarbutton.css({ 86 | 'margin-left': ssb_width_expanded-12, 87 | 'height': bodywrapper.height() 88 | }); 89 | sidebarbutton.find('span').text('«'); 90 | sidebarbutton.attr('title', _('Collapse sidebar')); 91 | document.cookie = 'sidebar=expanded'; 92 | } 93 | 94 | function add_sidebar_button() { 95 | sidebarwrapper.css({ 96 | 'float': 'left', 97 | 'margin-right': '0', 98 | 'width': ssb_width_expanded - 28 99 | }); 100 | // create the button 101 | sidebar.append( 102 | '
    «
    ' 103 | ); 104 | var sidebarbutton = $('#sidebarbutton'); 105 | light_color = sidebarbutton.css('background-color'); 106 | // find the height of the viewport to center the '<<' in the page 107 | var viewport_height; 108 | if (window.innerHeight) 109 | viewport_height = window.innerHeight; 110 | else 111 | viewport_height = $(window).height(); 112 | sidebarbutton.find('span').css({ 113 | 'display': 'block', 114 | 'margin-top': (viewport_height - sidebar.position().top - 20) / 2 115 | }); 116 | 117 | sidebarbutton.click(toggle_sidebar); 118 | sidebarbutton.attr('title', _('Collapse sidebar')); 119 | sidebarbutton.css({ 120 | 'color': '#FFFFFF', 121 | 'border-left': '1px solid ' + dark_color, 122 | 'font-size': '1.2em', 123 | 'cursor': 'pointer', 124 | 'height': bodywrapper.height(), 125 | 'padding-top': '1px', 126 | 'margin-left': ssb_width_expanded - 12 127 | }); 128 | 129 | sidebarbutton.hover( 130 | function () { 131 | $(this).css('background-color', dark_color); 132 | }, 133 | function () { 134 | $(this).css('background-color', light_color); 135 | } 136 | ); 137 | } 138 | 139 | function set_position_from_cookie() { 140 | if (!document.cookie) 141 | return; 142 | var items = document.cookie.split(';'); 143 | for(var k=0; k 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index — Django Admin Sortable 1.7.0 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 88 | 89 |
    90 | 91 | 92 | 96 | 97 | 98 | 99 |
    100 |
    101 |
    102 |
      103 |
    • Docs »
    • 104 | 105 |
    • 106 |
    • 107 | 108 |
    • 109 |
    110 |
    111 |
    112 |
    113 | 114 | 115 |

    Index

    116 | 117 |
    118 | 119 |
    120 | 121 | 122 |
    123 |
    124 | 125 | 126 |
    127 | 128 |
    129 |

    130 | © Copyright 2014, Brandon Taylor. 131 |

    132 |
    133 | 134 | Sphinx theme provided by Read the Docs 135 |
    136 |
    137 |
    138 | 139 |
    140 | 141 |
    142 | 143 | 144 | 145 | 146 | 147 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /docs/_build/html/testing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Testing — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 74 | 75 |
    76 | 77 | 78 | 82 | 83 | 84 | 85 |
    86 |
    87 |
    88 | 98 |
    99 |
    100 |
    101 | 102 |
    103 |

    Testing

    104 |

    Have a look at the included /sample_project directory to see a working project. The login credentials for admin are: admin/admin

    105 |

    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.

    106 |

    Inlines may be drag-and-dropped into any order directly from the change form.

    107 |

    Unit and functional tests may be found in the app/tests.py file and run via:

    108 |
    109 |
    $ python manage.py test app
    110 |
    111 | 112 | 113 |
    114 |
    115 | 116 | 122 | 123 | 124 |
    125 | 126 |
    127 |

    128 | © Copyright 2014, Brandon Taylor. 129 |

    130 |
    131 | 132 | Sphinx theme provided by Read the Docs 133 |
    134 |
    135 |
    136 | 137 |
    138 | 139 |
    140 | 141 | 142 | 143 | 144 | 145 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/_build/html/status.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Status — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 85 | 86 |
    87 | 88 | 89 | 93 | 94 | 95 | 96 |
    97 |
    98 |
    99 | 109 |
    110 |
    111 |
    112 | 113 |
    114 |

    Status

    115 |

    django-admin-sortable is stable and currently used in production.

    116 |
    117 | 118 | 119 |
    120 |
    121 | 122 | 128 | 129 | 130 |
    131 | 132 |
    133 |

    134 | © Copyright 2014, Brandon Taylor. 135 |

    136 |
    137 | 138 | Sphinx theme provided by Read the Docs 139 |
    140 |
    141 |
    142 | 143 |
    144 | 145 |
    146 | 147 | 148 | 149 | 150 | 151 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /docs/_build/html/known-issues.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Known Issue(s) — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
    43 | 44 | 45 | 81 | 82 |
    83 | 84 | 85 | 89 | 90 | 91 | 92 |
    93 |
    94 |
    95 | 105 |
    106 |
    107 |
    108 | 109 |
    110 |

    Known Issue(s)

    111 |

    Because of the way inline models are added to their parent model in the change form, it is not currently possible to have sortable inline models whose parent does not inhert from Sortable.

    112 |
    113 | 114 | 115 |
    116 |
    117 | 118 | 126 | 127 | 128 |
    129 | 130 |
    131 |

    132 | © Copyright 2014, Brandon Taylor. 133 |

    134 |
    135 | 136 | Sphinx theme provided by Read the Docs 137 |
    138 |
    139 |
    140 | 141 |
    142 | 143 |
    144 | 145 | 146 | 147 | 148 | 149 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /docs/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Search — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 | 42 | 43 | 87 | 88 |
    89 | 90 | 91 | 95 | 96 | 97 | 98 |
    99 |
    100 |
    101 |
      102 |
    • Docs »
    • 103 | 104 |
    • 105 |
    • 106 | 107 |
    • 108 |
    109 |
    110 |
    111 |
    112 | 113 | 121 | 122 | 123 |
    124 | 125 |
    126 | 127 |
    128 |
    129 | 130 | 131 |
    132 | 133 |
    134 |

    135 | © Copyright 2014, Brandon Taylor. 136 |

    137 |
    138 | 139 | Sphinx theme provided by Read the Docs 140 |
    141 |
    142 |
    143 | 144 |
    145 | 146 |
    147 | 148 | 149 | 150 | 151 | 152 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 181 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/_build/html/license.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | License — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 87 | 88 |
    89 | 90 | 91 | 95 | 96 | 97 | 98 |
    99 |
    100 |
    101 | 111 |
    112 |
    113 |
    114 | 115 |
    116 |

    License

    117 |

    django-admin-sortable is released under the Apache Public License v2.

    118 |
    119 | 120 | 121 |
    122 |
    123 | 124 | 130 | 131 | 132 |
    133 | 134 |
    135 |

    136 | © Copyright 2014, Brandon Taylor. 137 |

    138 |
    139 | 140 | Sphinx theme provided by Read the Docs 141 |
    142 |
    143 |
    144 | 145 |
    146 | 147 |
    148 | 149 | 150 | 151 | 152 | 153 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /docs/_build/html/future.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Future Plans — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 86 | 87 |
    88 | 89 | 90 | 94 | 95 | 96 | 97 |
    98 |
    99 |
    100 | 110 |
    111 |
    112 |
    113 | 114 |
    115 |

    Future Plans

    116 |
      117 |
    • Support for foreign keys that are self referential
    • 118 |
    • Move unit tests out of sample project (I could really use some help with this one)
    • 119 |
    • Travis CI integration
    • 120 |
    121 |
    122 | 123 | 124 |
    125 |
    126 | 127 | 133 | 134 | 135 |
    136 | 137 |
    138 |

    139 | © Copyright 2014, Brandon Taylor. 140 |

    141 |
    142 | 143 | Sphinx theme provided by Read the Docs 144 |
    145 |
    146 |
    147 | 148 |
    149 | 150 |
    151 | 152 | 153 | 154 | 155 | 156 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /adminsortable/models.py: -------------------------------------------------------------------------------- 1 | from django import VERSION 2 | from django.contrib.contenttypes.models import ContentType 3 | from django.db import models 4 | 5 | from adminsortable.fields import SortableForeignKey 6 | 7 | 8 | class MultipleSortableForeignKeyException(Exception): 9 | def __init__(self, value): 10 | self.value = value 11 | 12 | def __str__(self): 13 | return repr(self.value) 14 | 15 | 16 | class SortableMixin(models.Model): 17 | """ 18 | `is_sortable` determines whether or not the Model is sortable by 19 | determining if the last value of the field used to determine the order 20 | of objects is greater than the default of 1, which should be present if 21 | there is only one object. 22 | 23 | `model_type_id` returns the ContentType.id for the Model that 24 | inherits Sortable 25 | 26 | `save` the override of save increments the last/highest value of 27 | `Meta.ordering` by 1 28 | """ 29 | 30 | is_sortable = False 31 | sorting_filters = () 32 | 33 | # legacy support 34 | sortable_by = None 35 | sortable_foreign_key = None 36 | 37 | class Meta: 38 | abstract = True 39 | 40 | @classmethod 41 | def model_type_id(cls): 42 | return ContentType.objects.get_for_model(cls).id 43 | 44 | def __init__(self, *args, **kwargs): 45 | super(SortableMixin, self).__init__(*args, **kwargs) 46 | 47 | # Check that Meta.ordering contains one value 48 | try: 49 | self.order_field_name = self._meta.ordering[0].replace('-', '') 50 | except IndexError: 51 | raise ValueError(u'You must define the Meta.ordering ' 52 | u'property on your model.') 53 | 54 | # get the model field defined by `Meta.ordering` 55 | self.order_field = self._meta.get_field(self.order_field_name) 56 | 57 | integer_fields = (models.PositiveIntegerField, models.IntegerField, 58 | models.PositiveSmallIntegerField, models.SmallIntegerField, 59 | models.BigIntegerField,) 60 | 61 | # check that the order field is an integer type 62 | if not self.order_field or not isinstance(self.order_field, 63 | integer_fields): 64 | raise NotImplementedError(u'You must define the field ' 65 | '`Meta.ordering` refers to, and it must be of type: ' 66 | 'PositiveIntegerField, IntegerField, ' 67 | 'PositiveSmallIntegerField, SmallIntegerField, ' 68 | 'BigIntegerField') 69 | 70 | # Validate that model only contains at most one SortableForeignKey 71 | sortable_foreign_keys = [] 72 | for field in self._meta.fields: 73 | if isinstance(field, SortableForeignKey): 74 | sortable_foreign_keys.append(field) 75 | 76 | sortable_foreign_keys_length = len(sortable_foreign_keys) 77 | if sortable_foreign_keys_length > 1: 78 | raise MultipleSortableForeignKeyException( 79 | u'{0} may only have one SortableForeignKey'.format(self)) 80 | elif sortable_foreign_keys_length == 1: 81 | self.__class__.sortable_foreign_key = sortable_foreign_keys[0] 82 | 83 | def _get_order_field_value(self): 84 | try: 85 | return int(self.order_field.value_to_string(self)) 86 | except ValueError: 87 | raise u'The value from the specified order field could not be ' 88 | 'typecast to an integer.' 89 | 90 | def save(self, *args, **kwargs): 91 | needs_default = (self._state.adding if VERSION >= (1, 8) else not self.pk) 92 | if not getattr(self, self.order_field_name) and needs_default: 93 | try: 94 | current_max = self.__class__.objects.aggregate( 95 | models.Max(self.order_field_name))[self.order_field_name + '__max'] or 0 96 | 97 | setattr(self, self.order_field_name, current_max + 1) 98 | except (TypeError, IndexError): 99 | pass 100 | 101 | super(SortableMixin, self).save(*args, **kwargs) 102 | 103 | def _filter_objects(self, filters, filter_args, extra_filters, filter_kwargs, filter_on_sortable_fk): 104 | # DEPRECATION WARNING: `extra_filters` will be replaced by `filter_kwargs` in the next release 105 | 106 | if extra_filters: 107 | filters.update(extra_filters) 108 | 109 | if filter_kwargs: 110 | filters.update(filter_kwargs) 111 | 112 | if self.sortable_foreign_key and filter_on_sortable_fk: 113 | # sfk_obj == sortable foreign key instance 114 | sfk_obj = getattr(self, self.sortable_foreign_key.name) 115 | filters.update({ self.sortable_foreign_key.name: sfk_obj.id }) 116 | 117 | try: 118 | order_by = '-{0}'.format(self.order_field_name) \ 119 | if '{0}__lt'.format(self.order_field_name) in filters.keys() \ 120 | else self.order_field_name 121 | obj = self.__class__.objects.filter(*filter_args, **filters).order_by(order_by)[:1][0] 122 | except IndexError: 123 | obj = None 124 | 125 | return obj 126 | 127 | def get_next(self, filter_args=[], extra_filters={}, filter_kwargs={}, filter_on_sortable_fk=True): 128 | return self._filter_objects( 129 | {'{0}__gt'.format(self.order_field_name): self._get_order_field_value()}, 130 | filter_args, 131 | extra_filters, 132 | filter_kwargs, 133 | filter_on_sortable_fk 134 | ) 135 | 136 | def get_previous(self, filter_args=[], extra_filters={}, filter_kwargs={}, filter_on_sortable_fk=True): 137 | return self._filter_objects( 138 | {'{0}__lt'.format(self.order_field_name): self._get_order_field_value()}, 139 | filter_args, 140 | extra_filters, 141 | filter_kwargs, 142 | filter_on_sortable_fk 143 | ) 144 | 145 | 146 | # for legacy support of existing implementations 147 | class Sortable(SortableMixin): 148 | 149 | class Meta: 150 | abstract = True 151 | ordering = ['order'] 152 | 153 | order = models.PositiveIntegerField(default=0, editable=False, 154 | db_index=True) 155 | -------------------------------------------------------------------------------- /docs/_build/html/configuration.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Configuring Django Admin Sortable — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 73 | 74 |
    75 | 76 | 77 | 81 | 82 | 83 | 84 |
    85 |
    86 |
    87 |
      88 |
    • Docs »
    • 89 | 90 |
    • Configuring Django Admin Sortable
    • 91 |
    • 92 | 93 | View page source 94 | 95 |
    • 96 |
    97 |
    98 |
    99 |
    100 | 101 |
    102 |

    Configuring Django Admin Sortable

    103 |

    Configuring django-admin-sortable is quite simple:

    104 |
    105 |
      106 |
    1. Add adminsortable to your INSTALLED_APPS.
    2. 107 |
    3. Ensure django.core.context_processors.static is in your TEMPLATE_CONTEXT_PROCESSORS.
    4. 108 |
    109 |
    110 |
    111 |

    Static Media

    112 |

    django-admin-sortable includes a few CSS and JavaScript files. The preferred method of getting these files into your project is to use the staticfiles app.

    113 |

    Alternatively, you can copy or symlink the adminsortable folder inside the static directory to the location you serve static files from.

    114 |
    115 |
    116 | 117 | 118 |
    119 |
    120 | 121 | 127 | 128 | 129 |
    130 | 131 |
    132 |

    133 | © Copyright 2014, Brandon Taylor. 134 |

    135 |
    136 | 137 | Sphinx theme provided by Read the Docs 138 |
    139 |
    140 |
    141 | 142 |
    143 | 144 |
    145 | 146 | 147 | 148 | 149 | 150 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /sample_project/sample_project/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for test_project project. 2 | import os 3 | 4 | import django 5 | 6 | 7 | def map_path(directory_name): 8 | return os.path.join(os.path.dirname(__file__), 9 | '../' + directory_name).replace('\\', '/') 10 | 11 | 12 | DEBUG = True 13 | 14 | ADMINS = ( 15 | # ('Your Name', 'your_email@example.com'), 16 | ) 17 | 18 | MANAGERS = ADMINS 19 | 20 | DATABASES = { 21 | 'default': { 22 | 'ENGINE': 'django.db.backends.sqlite3', 23 | 'NAME': map_path('database/test_project.sqlite'), 24 | # The following settings are not used with sqlite3: 25 | 'USER': '', 26 | 'PASSWORD': '', 27 | 'HOST': '', 28 | 'PORT': '' 29 | } 30 | } 31 | 32 | # Hosts/domain names that are valid for this site; required if DEBUG is False 33 | # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts 34 | ALLOWED_HOSTS = [] 35 | 36 | # Local time zone for this installation. Choices can be found here: 37 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 38 | # although not all choices may be available on all operating systems. 39 | # In a Windows environment this must be set to your system time zone. 40 | TIME_ZONE = 'America/Chicago' 41 | 42 | # Language code for this installation. All choices can be found here: 43 | # http://www.i18nguy.com/unicode/language-identifiers.html 44 | LANGUAGE_CODE = 'en-us' 45 | 46 | SITE_ID = 1 47 | 48 | # If you set this to False, Django will make some optimizations so as not 49 | # to load the internationalization machinery. 50 | USE_I18N = True 51 | 52 | # If you set this to False, Django will not format dates, numbers and 53 | # calendars according to the current locale. 54 | USE_L10N = True 55 | 56 | # If you set this to False, Django will not use timezone-aware datetimes. 57 | USE_TZ = True 58 | 59 | # Absolute filesystem path to the directory that will hold user-uploaded files. 60 | # Example: "/var/www/example.com/media/" 61 | MEDIA_ROOT = '' 62 | 63 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 64 | # trailing slash. 65 | # Examples: "http://example.com/media/", "http://media.example.com/" 66 | MEDIA_URL = '' 67 | 68 | # Absolute path to the directory static files should be collected to. 69 | # Don't put anything in this directory yourself; store your static files 70 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 71 | # Example: "/var/www/example.com/static/" 72 | STATIC_ROOT = '' 73 | 74 | # URL prefix for static files. 75 | # Example: "http://example.com/static/", "http://static.example.com/" 76 | STATIC_URL = '/static/' 77 | 78 | # Additional locations of static files 79 | STATICFILES_DIRS = ( 80 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 81 | # Always use forward slashes, even on Windows. 82 | # Don't forget to use absolute paths, not relative paths. 83 | ) 84 | 85 | # List of finder classes that know how to find static files in 86 | # various locations. 87 | STATICFILES_FINDERS = ( 88 | 'django.contrib.staticfiles.finders.FileSystemFinder', 89 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 90 | ) 91 | 92 | # Make this unique, and don't share it with anybody. 93 | SECRET_KEY = '8**a!c8$1x)p@j2pj0yq!*v+dzp24g*$918ws#x@k+gf%0%rct' 94 | 95 | MIDDLEWARE = [ 96 | 'django.middleware.security.SecurityMiddleware', 97 | 'django.contrib.sessions.middleware.SessionMiddleware', 98 | 'django.middleware.common.CommonMiddleware', 99 | 'django.middleware.csrf.CsrfViewMiddleware', 100 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 101 | 'django.contrib.messages.middleware.MessageMiddleware', 102 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 103 | ] 104 | 105 | if django.VERSION < (1, 10): 106 | MIDDLEWARE_CLASSES = MIDDLEWARE 107 | 108 | ROOT_URLCONF = 'sample_project.urls' 109 | 110 | # Python dotted path to the WSGI application used by Django's runserver. 111 | WSGI_APPLICATION = 'sample_project.wsgi.application' 112 | 113 | TEMPLATES = [ 114 | { 115 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 116 | 'DIRS': [ 117 | map_path('templates'), 118 | ], 119 | 'APP_DIRS': True, 120 | 'OPTIONS': { 121 | 'context_processors': [ 122 | 'django.template.context_processors.debug', 123 | 'django.template.context_processors.request', 124 | 'django.contrib.auth.context_processors.auth', 125 | 'django.contrib.messages.context_processors.messages', 126 | ], 127 | }, 128 | }, 129 | ] 130 | 131 | INSTALLED_APPS = ( 132 | 'django.contrib.auth', 133 | 'django.contrib.contenttypes', 134 | 'django.contrib.sessions', 135 | 'django.contrib.sites', 136 | 'django.contrib.messages', 137 | 'django.contrib.staticfiles', 138 | 'django.contrib.admin', 139 | 'django.contrib.admindocs', 140 | 141 | 'adminsortable', 142 | 'samples', 143 | ) 144 | 145 | # A sample logging configuration. The only tangible logging 146 | # performed by this configuration is to send an email to 147 | # the site admins on every HTTP 500 error when DEBUG=False. 148 | # See http://docs.djangoproject.com/en/dev/topics/logging for 149 | # more details on how to customize your logging configuration. 150 | LOGGING = { 151 | 'version': 1, 152 | 'disable_existing_loggers': False, 153 | 'filters': { 154 | 'require_debug_false': { 155 | '()': 'django.utils.log.RequireDebugFalse' 156 | } 157 | }, 158 | 'handlers': { 159 | 'mail_admins': { 160 | 'level': 'ERROR', 161 | 'filters': ['require_debug_false'], 162 | 'class': 'django.utils.log.AdminEmailHandler' 163 | } 164 | }, 165 | 'loggers': { 166 | 'django.request': { 167 | 'handlers': ['mail_admins'], 168 | 'level': 'ERROR', 169 | 'propagate': True, 170 | }, 171 | } 172 | } 173 | 174 | # Password validation 175 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 176 | 177 | AUTH_PASSWORD_VALIDATORS = [ 178 | { 179 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 180 | }, 181 | { 182 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 183 | }, 184 | { 185 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 186 | }, 187 | { 188 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 189 | }, 190 | ] 191 | 192 | DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' -------------------------------------------------------------------------------- /docs/_build/html/rationale.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Rationale — Django Admin Sortable 1.7.0 documentation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
    42 | 43 | 44 | 84 | 85 |
    86 | 87 | 88 | 92 | 93 | 94 | 95 |
    96 |
    97 |
    98 | 108 |
    109 |
    110 |
    111 | 112 |
    113 |

    Rationale

    114 |
    115 |

    Why another drag-and-drop ordering plugin?

    116 |

    Other projects have added drag-and-drop ordering to the ChangeList view, however this introduces a couple of problems...

    117 |
      118 |
    • The ChangeList view supports pagination, which makes drag-and-drop ordering across pages impossible.
    • 119 |
    • 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.
    • 120 |
    • The ChangeList supports in-line editing, and adding drag-and-drop ordering on top of that just seemed a little much in my opinion.
    • 121 |
    122 |
    123 |
    124 | 125 | 126 |
    127 |
    128 | 129 | 135 | 136 | 137 |
    138 | 139 |
    140 |

    141 | © Copyright 2014, Brandon Taylor. 142 |

    143 |
    144 | 145 | Sphinx theme provided by Read the Docs 146 |
    147 |
    148 |
    149 | 150 |
    151 | 152 |
    153 | 154 | 155 | 156 | 157 | 158 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /docs/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilities for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | }; 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * highlight a given string on a jquery object by wrapping it in 66 | * span elements with the given class name. 67 | */ 68 | jQuery.fn.highlightText = function(text, className) { 69 | function highlight(node) { 70 | if (node.nodeType == 3) { 71 | var val = node.nodeValue; 72 | var pos = val.toLowerCase().indexOf(text); 73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 | var span = document.createElement("span"); 75 | span.className = className; 76 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 | document.createTextNode(val.substr(pos + text.length)), 79 | node.nextSibling)); 80 | node.nodeValue = val.substr(0, pos); 81 | } 82 | } 83 | else if (!jQuery(node).is("button, select, textarea")) { 84 | jQuery.each(node.childNodes, function() { 85 | highlight(this); 86 | }); 87 | } 88 | } 89 | return this.each(function() { 90 | highlight(this); 91 | }); 92 | }; 93 | 94 | /** 95 | * Small JavaScript module for the documentation. 96 | */ 97 | var Documentation = { 98 | 99 | init : function() { 100 | this.fixFirefoxAnchorBug(); 101 | this.highlightSearchWords(); 102 | this.initIndexTable(); 103 | }, 104 | 105 | /** 106 | * i18n support 107 | */ 108 | TRANSLATIONS : {}, 109 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 110 | LOCALE : 'unknown', 111 | 112 | // gettext and ngettext don't access this so that the functions 113 | // can safely bound to a different name (_ = Documentation.gettext) 114 | gettext : function(string) { 115 | var translated = Documentation.TRANSLATIONS[string]; 116 | if (typeof translated == 'undefined') 117 | return string; 118 | return (typeof translated == 'string') ? translated : translated[0]; 119 | }, 120 | 121 | ngettext : function(singular, plural, n) { 122 | var translated = Documentation.TRANSLATIONS[singular]; 123 | if (typeof translated == 'undefined') 124 | return (n == 1) ? singular : plural; 125 | return translated[Documentation.PLURALEXPR(n)]; 126 | }, 127 | 128 | addTranslations : function(catalog) { 129 | for (var key in catalog.messages) 130 | this.TRANSLATIONS[key] = catalog.messages[key]; 131 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 132 | this.LOCALE = catalog.locale; 133 | }, 134 | 135 | /** 136 | * add context elements like header anchor links 137 | */ 138 | addContextElements : function() { 139 | $('div[id] > :header:first').each(function() { 140 | $('\u00B6'). 141 | attr('href', '#' + this.id). 142 | attr('title', _('Permalink to this headline')). 143 | appendTo(this); 144 | }); 145 | $('dt[id]').each(function() { 146 | $('\u00B6'). 147 | attr('href', '#' + this.id). 148 | attr('title', _('Permalink to this definition')). 149 | appendTo(this); 150 | }); 151 | }, 152 | 153 | /** 154 | * workaround a firefox stupidity 155 | */ 156 | fixFirefoxAnchorBug : function() { 157 | if (document.location.hash && $.browser.mozilla) 158 | window.setTimeout(function() { 159 | document.location.href += ''; 160 | }, 10); 161 | }, 162 | 163 | /** 164 | * highlight the search words provided in the url in the text 165 | */ 166 | highlightSearchWords : function() { 167 | var params = $.getQueryParameters(); 168 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 169 | if (terms.length) { 170 | var body = $('div.body'); 171 | if (!body.length) { 172 | body = $('body'); 173 | } 174 | window.setTimeout(function() { 175 | $.each(terms, function() { 176 | body.highlightText(this.toLowerCase(), 'highlighted'); 177 | }); 178 | }, 10); 179 | $('') 181 | .appendTo($('#searchbox')); 182 | } 183 | }, 184 | 185 | /** 186 | * init the domain index toggle buttons 187 | */ 188 | initIndexTable : function() { 189 | var togglers = $('img.toggler').click(function() { 190 | var src = $(this).attr('src'); 191 | var idnum = $(this).attr('id').substr(7); 192 | $('tr.cg-' + idnum).toggle(); 193 | if (src.substr(-9) == 'minus.png') 194 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 195 | else 196 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 197 | }).css('display', ''); 198 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 199 | togglers.click(); 200 | } 201 | }, 202 | 203 | /** 204 | * helper function to hide the search marks again 205 | */ 206 | hideSearchWords : function() { 207 | $('#searchbox .highlight-link').fadeOut(300); 208 | $('span.highlighted').removeClass('highlighted'); 209 | }, 210 | 211 | /** 212 | * make the url absolute 213 | */ 214 | makeURL : function(relativeURL) { 215 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 216 | }, 217 | 218 | /** 219 | * get the current relative url 220 | */ 221 | getCurrentURL : function() { 222 | var path = document.location.pathname; 223 | var parts = path.split(/\//); 224 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 225 | if (this == '..') 226 | parts.pop(); 227 | }); 228 | var url = parts.join('/'); 229 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 230 | } 231 | }; 232 | 233 | // quick alias for translations 234 | _ = Documentation.gettext; 235 | 236 | $(document).ready(function() { 237 | Documentation.init(); 238 | }); 239 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | clean: 51 | rm -rf $(BUILDDIR)/* 52 | 53 | html: 54 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 55 | @echo 56 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 57 | 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | singlehtml: 64 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 65 | @echo 66 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 67 | 68 | pickle: 69 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 70 | @echo 71 | @echo "Build finished; now you can process the pickle files." 72 | 73 | json: 74 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 75 | @echo 76 | @echo "Build finished; now you can process the JSON files." 77 | 78 | htmlhelp: 79 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 80 | @echo 81 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 82 | ".hhp project file in $(BUILDDIR)/htmlhelp." 83 | 84 | qthelp: 85 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 86 | @echo 87 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 88 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 89 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DjangoAdminSortable.qhcp" 90 | @echo "To view the help file:" 91 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoAdminSortable.qhc" 92 | 93 | devhelp: 94 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 95 | @echo 96 | @echo "Build finished." 97 | @echo "To view the help file:" 98 | @echo "# mkdir -p $$HOME/.local/share/devhelp/DjangoAdminSortable" 99 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DjangoAdminSortable" 100 | @echo "# devhelp" 101 | 102 | epub: 103 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 104 | @echo 105 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 106 | 107 | latex: 108 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 109 | @echo 110 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 111 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 112 | "(use \`make latexpdf' here to do that automatically)." 113 | 114 | latexpdf: 115 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 116 | @echo "Running LaTeX files through pdflatex..." 117 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 118 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 119 | 120 | latexpdfja: 121 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 122 | @echo "Running LaTeX files through platex and dvipdfmx..." 123 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 124 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 125 | 126 | text: 127 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 128 | @echo 129 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 130 | 131 | man: 132 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 133 | @echo 134 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 135 | 136 | texinfo: 137 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 138 | @echo 139 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 140 | @echo "Run \`make' in that directory to run these through makeinfo" \ 141 | "(use \`make info' here to do that automatically)." 142 | 143 | info: 144 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 145 | @echo "Running Texinfo files through makeinfo..." 146 | make -C $(BUILDDIR)/texinfo info 147 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 148 | 149 | gettext: 150 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 151 | @echo 152 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 153 | 154 | changes: 155 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 156 | @echo 157 | @echo "The overview file is in $(BUILDDIR)/changes." 158 | 159 | linkcheck: 160 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 161 | @echo 162 | @echo "Link check complete; look for any errors in the above output " \ 163 | "or in $(BUILDDIR)/linkcheck/output.txt." 164 | 165 | doctest: 166 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 167 | @echo "Testing of doctests in the sources finished, look at the " \ 168 | "results in $(BUILDDIR)/doctest/output.txt." 169 | 170 | coverage: 171 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 172 | @echo "Testing of coverage in the sources finished, look at the " \ 173 | "results in $(BUILDDIR)/coverage/python.txt." 174 | 175 | xml: 176 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 177 | @echo 178 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 179 | 180 | pseudoxml: 181 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 182 | @echo 183 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 184 | --------------------------------------------------------------------------------