Modelos ordenados¶
Substitui o django-ordered-model. move_to(n) atômico e inlines com HTML5 Drag & Drop, ~120 LOC.

Modelo¶
from django.db import models
from django_yp_admin.models import OrderedModel
class Album(models.Model):
name = models.CharField(max_length=100)
class Track(OrderedModel):
title = models.CharField(max_length=100)
album = models.ForeignKey(Album, on_delete=models.CASCADE, related_name="tracks")
order_with_respect_to = "album" # separate sequences per album
class Meta(OrderedModel.Meta):
constraints = [
models.UniqueConstraint(
fields=["album", "order"],
name="track_album_order_uniq",
)
]
order_with_respect_to aceita uma string (uma FK) ou uma tupla de strings (agrupamento multi-chave).
Concorrência: declare um UniqueConstraint¶
move_to() usa select_for_update(), mas um UniqueConstraint em nível de banco de dados sobre os campos de order_with_respect_to mais order é obrigatório para evitar que duas transações concorrentes produzam linhas com ordem duplicada. As subclasses DEVEM declará-lo elas mesmas — OrderedModel é abstrato e o conjunto de campos é específico de cada subclasse.
Para modelos sem order_with_respect_to, restrinja ["order"] sozinho ou marque o campo order com unique=True.
API¶
instance.order— a posição atual. Atribuída automaticamente nosave()se faltante.instance.move_to(n)— desloca atomicamente esta linha para a posiçãon. As linhas irmãs em(old, new](ou[new, old)) são deslocadas em ±1 num únicoUPDATE … SET order = order + 1sobselect_for_update().
last = Track.objects.filter(album=album).last()
last.move_to(0) # promote to first
Drag & Drop no admin¶
from django_yp_admin.contrib.ordered_admin import OrderedAdmin
from django_yp_admin.options import TabularInline
class TrackInline(TabularInline):
model = Track
sortable_field = "order" # enables HTML5 DnD + htmx reorder endpoint
@admin.register(Album)
class AlbumAdmin(ModelAdmin):
inlines = [TrackInline]
Sem jQuery UI. A reordenação chega ao endpoint views/reorder.py via htmx e as linhas trocam visualmente na hora.