django-ordered-model

repository·master·Indexed 20 days ago

https://github.com/django-ordered-model/django-ordered-model

A Django library for managing ordered models, providing methods to manipulate object positions (up, down, swap, move to top/bottom) and a simple admin interface for reordering. It includes support for subset ordering via order_with_respect_to, OrderedManyToManyField for many-to-many relationships, and integration with Django Rest Framework via OrderedModelSerializer. The package also provides a reorder_model management command to fix inconsistent ordering states in the database.

Tokens
3.1K
Snippets
17
Records
17
Agent score
23%

What's inside django-ordered-model

  1. Use Subset Ordering with `order_with_respect_to`

    master

    If you need to order objects within specific groups (e.g., contacts belonging to different users), use the order_with_respect_to attribute. This ensures that the ordering of one group does not affect the ordering of another.

    Single Field

    Set order_with_respect_to to the name of a ForeignKey field.

    Multiple Fields

    Pass a tuple of field names to define ordering across multiple dimensions.

    You can use the double-underscore syntax to specify a field on a related model (e.g., 'group__user').

    Note: order_with_respect_to must specify a ForeignKey field on the model, otherwise a Django Check error (E002, E005, or E006) will be raised.

    class Contact(OrderedModel):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        phone = models.CharField()
        order_with_respect_to = 'user'
    
    # Multiple fields
    class Model(OrderedModel):
        order_with_respect_to = ('field_a', 'field_b')
    
    # Related model field
    class GroupedItem(OrderedModel):
        group = models.ForeignKey(ItemGroup, on_delete=models.CASCADE)
        order_with_respect_to = 'group__user'
  2. Integrate reordering into Django Admin

    master

    To enable drag-and-drop style reordering arrows in the Django Admin:

    For Standard Models

    Use OrderedModelAdmin and include move_up_down_links in your list_display.

    For ManyToMany Inlines

    Use OrderedTabularInline or OrderedStackedInline. When using these in an admin class, ensure the admin class also inherits from OrderedInlineModelAdminMixin to ensure URL routes are registered correctly.

    # Standard Model Admin
    from django.contrib import admin
    from ordered_model.admin import OrderedModelAdmin
    
    class ItemAdmin(OrderedModelAdmin):
        list_display = ('name', 'move_up_down_links')
    
    admin.site.register(Item, ItemAdmin)
    
    # ManyToMany Inline Admin
    from ordered_model.admin import OrderedTabularInline, OrderedInlineModelAdminMixin
    
    class PizzaToppingsTabularInline(OrderedTabularInline):
        model = PizzaToppingsThroughModel
        fields = ('topping', 'order', 'move_up_down_links',)
        readonly_fields = ('order', 'move_up_down_links',)
        ordering = ('order',)
        extra = 1
    
    class PizzaAdmin(OrderedInlineModelAdminMixin, admin.ModelAdmin):
        inlines = (PizzaToppingsTabularInline,)
    
    admin.site.register(Pizza, PizzaAdmin)
  3. Configure and use OrderedModel

    master

    To use django-ordered-model, follow these steps:

    1. Add 'ordered_model' to your INSTALLED_APPS in Django settings.py.
    2. Inherit your model from ordered_model.models.OrderedModel.
    3. Run python manage.py makemigrations and python manage.py migrate to create the necessary ordering fields in your database.

    Example:

    from django.db import models
    from ordered_model.models import OrderedModel
    
    
    class Item(OrderedModel):
        name = models.CharField(max_length=100)
  4. Include extra fields when updating shifted objects

    master

    Methods like delete(), to(), below(), above(), top(), and bottom() use Django's update() method for performance when shifting other objects. If you need to update specific fields (like a modified timestamp) on the objects being shifted, use the extra_update argument.

    Note: This affects the objects being shifted, not the target object itself.

    foo.to(12, extra_update={'modified': now()})
  5. Use a custom field for ordering

    master

    By default, OrderedModel creates a models.PositiveIntegerField named order. If you want to use an existing field for ordering, subclass OrderedModelBase instead of OrderedModel.

    You must set order_field_name to the name of your field and ensure your Meta.ordering includes that field.

    from ordered_model.models import OrderedModelBase
    
    class MyModel(OrderedModelBase):
        sort_order = models.PositiveIntegerField(editable=False, db_index=True)
        order_field_name = "sort_order"
    
        class Meta:
            ordering = ("sort_order",)
  6. Order ManyToMany relationships using `OrderedManyToManyField`

    master

    Standard Django ManyToManyField results do not respect the Meta.ordering of the intermediate (through) model. To ensure that calling .all() on a many-to-many relationship returns objects in the correct order, use OrderedManyToManyField from ordered_model.fields.

    This field automatically applies the necessary ordering clause to the queryset.

    from ordered_model.fields import OrderedManyToManyField
    
    class Pizza(models.Model):
        name = models.CharField(max_length=100)
        toppings = OrderedManyToManyField(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")