All Projects → bfirsh → Django Ordered Model

bfirsh / Django Ordered Model

Licence: other
Get your Django models in order

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to Django Ordered Model

Django Practice Book
《Django企业开发实战》已出版
Stars: ✭ 251 (-47.27%)
Mutual labels:  django, django-admin
Django Admin Easy
Collection of admin fields and decorators to help to create computed or custom fields more friendly and easy way
Stars: ✭ 265 (-44.33%)
Mutual labels:  django, django-admin
Django Mptt Admin
Django-mptt-admin provides a nice Django Admin interface for Mptt models
Stars: ✭ 256 (-46.22%)
Mutual labels:  django, django-admin
Django Admin Env Notice
Visually distinguish environments in Django Admin
Stars: ✭ 207 (-56.51%)
Mutual labels:  django, django-admin
Django Nested Admin
Django admin classes that allow for nested inlines
Stars: ✭ 463 (-2.73%)
Mutual labels:  django, django-admin
Django Admin List Filter Dropdown
Use dropdowns in Django admin list filter
Stars: ✭ 215 (-54.83%)
Mutual labels:  django, django-admin
Django Fluent Dashboard
An improved django-admin-tools dashboard for Django projects
Stars: ✭ 266 (-44.12%)
Mutual labels:  django, django-admin
Django Inline Actions
django-inline-actions adds actions to each row of the ModelAdmin or InlineModelAdmin.
Stars: ✭ 170 (-64.29%)
Mutual labels:  django, django-admin
Awesome Django Admin
Curated List of Awesome Django Admin Panel Articles, Libraries/Packages, Books, Themes, Videos, Resources.
Stars: ✭ 356 (-25.21%)
Mutual labels:  django, django-admin
Djangocms Admin Style
django CMS Admin Style is a Django Theme tailored to the needs of django CMS.
Stars: ✭ 282 (-40.76%)
Mutual labels:  django, django-admin
Repoll
Redis管理平台Repoll,现已开源,基于redis3.x,支持单机、哨兵以及集群模式
Stars: ✭ 196 (-58.82%)
Mutual labels:  django, django-admin
Django Object Actions
A Django app for easily adding object tools in the Django admin
Stars: ✭ 374 (-21.43%)
Mutual labels:  django, django-admin
Django Suit
Modern theme for Django admin interface
Stars: ✭ 2,136 (+348.74%)
Mutual labels:  django, django-admin
Django Flat Responsive
📱 An extension for Django admin that makes interface mobile-friendly. Merged into Django 2.0
Stars: ✭ 249 (-47.69%)
Mutual labels:  django, django-admin
Django Antd Tyadmin
类似 xadmin 的基于Model 快速生成前后台管理增删改查,筛选,搜索的后台管理自动化工具。Antd 界面好看现代化!前后端分离!无损二次开发!由Django Restful Framework 和 Ant Design Pro V4 驱动
Stars: ✭ 171 (-64.08%)
Mutual labels:  django, django-admin
Django Wpadmin
WordPress look and feel for Django administration panel
Stars: ✭ 259 (-45.59%)
Mutual labels:  django, django-admin
Django Material Admin
Material design for django administration
Stars: ✭ 163 (-65.76%)
Mutual labels:  django, django-admin
Django Admin Autocomplete Filter
A simple Django app to render list filters in django admin using autocomplete widget.
Stars: ✭ 166 (-65.13%)
Mutual labels:  django, django-admin
Django Page Cms
Official Django page CMS git repository
Stars: ✭ 277 (-41.81%)
Mutual labels:  django, django-admin
Django Cruds Adminlte
django-cruds is simple drop-in django app that creates CRUD for faster prototyping
Stars: ✭ 373 (-21.64%)
Mutual labels:  django, django-admin

django-ordered-model

Build Status PyPI version codecov Code style: black

django-ordered-model allows models to be ordered and provides a simple admin interface for reordering them.

Based on https://djangosnippets.org/snippets/998/ and https://djangosnippets.org/snippets/259/

See our compatability notes for the appropriate version to use with older Django and Python releases.

Installation

$ python setup.py install

You can use Pip:

$ pip install django-ordered-model

Usage

Add ordered_model to your SETTINGS.INSTALLED_APPS.

Inherit your model from OrderedModel to make it ordered:

from django.db import models
from ordered_model.models import OrderedModel


class Item(OrderedModel):
    name = models.CharField(max_length=100)

    class Meta(OrderedModel.Meta):
        pass

Model instances now have a set of methods to move them relative to each other. To demonstrate those methods we create two instances of Item:

foo = Item.objects.create(name="Foo")
bar = Item.objects.create(name="Bar")

Swap positions

foo.swap(bar)

This swaps the position of two objects.

Move position up on position

foo.up()
foo.down()

Moving an object up or down just makes it swap its position with the neighbouring object directly above of below depending on the direction.

Move to arbitrary position

foo.to(12)
bar.to(13)

Move the object to an arbitrary position in the stack. This essentially sets the order value to the specified integer. Objects between the original and the new position get their order value increased or decreased according to the direction of the move.

Move object above or below reference

foo.above(bar)
foo.below(bar)

Move the object directly above or below the reference object, increasing or decreasing the order value for all objects between the two, depending on the direction of the move.

Move to top of stack

foo.top()

This sets the order value to the lowest value found in the stack and increases the order value of all objects that were above the moved object by one.

Move to bottom of stack

foo.bottom()

This sets the order value to the highest value found in the stack and decreases the order value of all objects that were below the moved object by one.

Updating fields that would be updated during save()

For performance reasons, the delete(), to(), below(), above(), top(), and bottom() methods use Django's update() method to change the order of other objects that are shifted as a result of one of these calls. If the model has fields that are typically updated in a customized save() method, or through other app level functionality such as DateTimeField(auto_now=True), you can add additional fields to be passed through to update(). This will only impact objects where their order is being shifted as a result of an operation on the target object, not the target object itself.

foo.to(12, extra_update={'modified': now()})

Get the previous or next objects

foo.previous()
foo.next()

previous() and next() get the neighbouring objects directly above of below within the ordered stack depending on the direction.

Subset Ordering

In some cases, ordering objects is required only on a subset of objects. For example, an application that manages contact lists for users, in a many-to-one/many relationship, would like to allow each user to order their contacts regardless of how other users choose their order. This option is supported via the order_with_respect_to parameter.

A simple example might look like so:

class Contact(OrderedModel):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    phone = models.CharField()
    order_with_respect_to = 'user'

If objects are ordered with respect to more than one field, order_with_respect_to supports tuples to define multiple fields:

class Model(OrderedModel)
    # ...
    order_with_respect_to = ('field_a', 'field_b')

In a many-to-many relationship you need to use a separate through model which is derived from the OrderedModel. For example, an application which manages pizzas with toppings.

A simple example might look like so:

class Topping(models.Model):
    name = models.CharField(max_length=100)


class Pizza(models.Model):
    name = models.CharField(max_length=100)
    toppings = models.ManyToManyField(Topping, through='PizzaToppingsThroughModel')


class PizzaToppingsThroughModel(OrderedModel):
    pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)
    topping = models.ForeignKey(Topping, on_delete=models.CASCADE)
    order_with_respect_to = 'pizza'

    class Meta:
        ordering = ('pizza', 'order')

You can also specify order_with_respect_to to a field on a related model. An example use-case can be made with the following models:

class ItemGroup(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    general_info = models.CharField(max_length=100)

class GroupedItem(OrderedModel):
    group = models.ForeignKey(ItemGroup, on_delete=models.CASCADE)
    specific_info = models.CharField(max_length=100)
    order_with_respect_to = 'group__user'

Here items are put into groups that have some general information used by its items, but the ordering of the items is independent of the group the item is in.

When you want ordering on the baseclass instead of subclasses in an ordered list of objects of various classes, specify the full module path of the base class:

class BaseQuestion(OrderedModel):
    order_class_path = __module__ + '.BaseQuestion'
    question = models.TextField(max_length=100)

    class Meta:
        ordering = ('order',)

class MultipleChoiceQuestion(BaseQuestion):
    good_answer = models.TextField(max_length=100)
    wrong_answer1 = models.TextField(max_length=100)
    wrong_answer2 = models.TextField(max_length=100)
    wrong_answer3 = models.TextField(max_length=100)

class OpenQuestion(BaseQuestion):
    answer = models.TextField(max_length=100)

Custom Manager and QuerySet

When your model your extends OrderedModel, it inherits a custom ModelManager instance, OrderedModelManager, which provides additional operations on the resulting QuerySet. For example an OrderedModel subclass called Item that returns a queryset from Item.objects.all() supports the following functions:

  • above_instance(object),
  • below_instance(object),
  • get_min_order(),
  • get_max_order(),
  • above(index),
  • below(index)

If your model defines a custom ModelManager such as ItemManager below, you may wish to extend OrderedModelManager to retain those functions, as follows:

from ordered_model.models import OrderedModelManager, OrderedModel

class ItemManager(OrderedModelManager):
    pass

class Item(OrderedModel):
    objects = ItemManager()

Custom ordering field

Extending OrderedModel creates a models.PositiveIntegerField field called order and the appropriate migrations. If you wish to use an existing model field to store the ordering, you can set the attribute order_field_name to match your field name:

class MyModel(OrderedModelBase):
    ...
    sort_order = models.PositiveIntegerField(editable=False, db_index=True)
    order_field_name = "sort_order"

    class Meta:
        ordering = ("sort_order",)

See tests/models.py object CustomOrderFieldModel for an example.

Admin integration

To add arrows in the admin change list page to do reordering, you can use the OrderedModelAdmin and the move_up_down_links field:

from django.contrib import admin
from ordered_model.admin import OrderedModelAdmin
from models import Item


class ItemAdmin(OrderedModelAdmin):
    list_display = ('name', 'move_up_down_links')

admin.site.register(Item, ItemAdmin)

For a many-to-many relationship you need one of the following inlines.

OrderedTabularInline or OrderedStackedInline just like the django admin.

For the OrderedTabularInline it will look like this:

from django.contrib import admin
from ordered_model.admin import OrderedTabularInline, OrderedInlineModelAdminMixin
from models import Pizza, PizzaToppingsThroughModel


class PizzaToppingsThroughModelTabularInline(OrderedTabularInline):
    model = PizzaToppingsThroughModel
    fields = ('topping', 'order', 'move_up_down_links',)
    readonly_fields = ('order', 'move_up_down_links',)
    extra = 1
    ordering = ('order',)


class PizzaAdmin(OrderedInlineModelAdminMixin, admin.ModelAdmin):
    list_display = ('name', )
    inlines = (PizzaToppingsThroughModelTabularInline, )


admin.site.register(Pizza, PizzaAdmin)

For the OrderedStackedInline it will look like this:

from django.contrib import admin
from ordered_model.admin import OrderedStackedInline, OrderedInlineModelAdminMixin
from models import Pizza, PizzaToppingsThroughModel


class PizzaToppingsThroughModelStackedInline(OrderedStackedInline):
    model = PizzaToppingsThroughModel
    fields = ('topping', 'order', 'move_up_down_links',)
    readonly_fields = ('order', 'move_up_down_links',)
    extra = 1
    ordering = ('order',)


class PizzaAdmin(OrderedInlineModelAdminMixin, admin.ModelAdmin):
    list_display = ('name', )
    inlines = (PizzaToppingsThroughModelStackedInline, )


admin.site.register(Pizza, PizzaAdmin)

Test suite

Requires Docker.

$ script/test

Compatibility with Django and Python

django-ordered-model version Django version Python version
3.4.x 2.x 3.5 and above
3.3.x 2.x 3.4 and above
3.2.x 2.x 3.4 and above
3.1.x 2.x 3.4 and above
3.0.x 2.x 3.4 and above
2.1.x 1.x 2.7 to 3.6
2.0.x 1.x 2.7 to 3.6

Maintainers

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].