Сортировка HTMX работает только один раз, рендеринг делает ее нерабочей

Я ссылаюсь на канал BugBytes на YouTube о сортируемом меню в Django.

(Django и HTMX #6 (часть 1) - Построение сортируемого интерфейса перетаскивания и падения )

https://www.youtube.com/watch?v=V-f_yYKUJo8

(Django и HTMX #6 (часть 2) - Построение сортируемого интерфейса перетаскивания и падения )

https://www.youtube.com/watch?v=5Fuwo4tVXmE

Некоторые люди столкнулись с той же проблемой, но нашли подсказку, как ее решить.

Я не мог иметь никакого подтекста.

Тот же вопрос найден в StackOverflow здесь. "Sortable JS breaks upon htmx rendering a partial"

И я не думаю, что ответ показывает какие-либо решения.

В моем случае, следуя обучающему видео BugBytes и репозиторию , я сделал следующие файлы Django.

books.html

<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>List Books</title>
  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>

  <script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
  
</head>
<body>


  <section id="book_list">
    {% include 'list_books.html' %}
  </section>




  <script>
    document.body.addEventListener('htmx:configRequest', (event) => {
        event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
    })
    htmx.onLoad(function(content) {
        var sortables = content.querySelectorAll(".sortable");
        for (var i = 0; i < sortables.length; i++) {
          var sortable = sortables[i];
          new Sortable(sortable, {
              animation: 150,
              ghostClass: 'blue-background-class'
          });
        }
    })

  </script>
</body>
</html>

list_books.html

    {% csrf_token %}
  <form class="sortable" hx-post="{% url 'book_app:sort' %}" hx-trigger="end" hx-target="#book_list" hx-swap="innerHTML">
    <div class="htmx-indicator">Updating...</div>
    
    {% for book in all_books %}
    <div>
        <input type='hidden' name='book_order' value='{{ book.pk }}'/>
      <p>#{{ book.order }} / {{ book.category.large_category }}/{{ book.category }}/{{ book.title }}</p>
    </div>
    {% endfor %}

  </form>

urls.py

from django.urls import path
from . import views

app_name = 'book_app'

urlpatterns = [
    path('books/', views.books, name='books'),
]

htmx_urlpatterns = [
    path('sort/', views.sort, name='sort'),
]

urlpatterns += htmx_urlpatterns

views.py


def books(request):
    all_books = Books.objects.all().order_by('order')
    context = {
        'all_books': all_books,
    }
    return render(request, 'books.html', context)

def sort(request):
    books_order_list = request.POST.getlist('book_order')
    print(books_order_list)
    all_books = []
    for idx, book_pk in enumerate(books_order_list, start=1):
        book = Books.objects.get(pk=book_pk)
        book.order = idx
        book.save()
        all_books.append(book)
    context = {
        'all_books': all_books,
    }
    return render(request, 'list_books.html', context)

models.py

from django.db import models

# Create your models here.

class LargeCategory(models.Model):
    name = models.CharField(max_length=25)

    def __str__(self):
        return self.name

class SmallCategory(models.Model):
    large_category = models.ForeignKey(LargeCategory, on_delete=models.CASCADE)
    name = models.CharField(max_length=25)

    def __str__(self):
        return self.name


class Books(models.Model):
    category = models.ForeignKey(SmallCategory, on_delete=models.CASCADE)
    title = models.CharField(max_length=25)
    order = models.PositiveSmallIntegerField(null=True, blank=True)

Я заметил, пока собирался разместить этот вопрос, что если я изменю целевой файл для рендеринга о функции sort() в файле views.py???

Поэтому я изменил функцию sort() в файле views.py следующим образом!!!


def sort(request):
    books_order_list = request.POST.getlist('book_order')
    print(books_order_list)
    all_books = []
    for idx, book_pk in enumerate(books_order_list, start=1):
        book = Books.objects.get(pk=book_pk)
        book.order = idx
        book.save()
        all_books.append(book)
    context = {
        'all_books': all_books,
    }
    return render(request, 'books.html', context)

Я изменяю целевой файл шаблона для рендеринга типа "list_books.html" на "books.html".

И наконец-то все работает нормально!!!

В обучающем видео от BugBytes целевой файл шаблона функции sort() в файле views.py при повторной проверке становится "film-list.html".

Надеюсь, это будет полезно для будущих студентов.

Потому что мало ресурсов для справки о HTMX и сортируемом классе этого.

Счастливое кодирование!!! :D!!

Вернуться на верх