如何正确将任意位置的对象插入到现有查询集中并按顺序更新顺序?



我有两个模型BookChapters具有外键关系。

我正在尝试在已存在的章节QuerySet之间INSERT按字段排序orderChapter,但在以下方面遇到麻烦:

  1. INSERT后按顺序维护order
  2. 当切片操作
  3. 变为负数时处理切片操作(QuerySet不允许负索引(。
  4. 处理非顺序订单。

例:

假设我已经有第 1 章到第 10 章了。现在我需要在 1 和 2 之间添加一个新章节。因此,新章节应该取代数据库中当前的第2章。因此,2之后的所有章节,包括它自己都应该有一个order + 1order,以便为新章节腾出空间。

我的代码:

models.py

class Book(PubDateUpdDateMixin, models.Model):
title = models.CharField(max_length=80)
slug = models.SlugField(unique=True, blank=True)
description = models.CharField(max_length=3000)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='authors')
class chapter(PubDateUpdDateMixin, models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='chapters')
title = models.CharField(max_length=40)
content = models.TextField(max_length=30000)
slug = models.SlugField(unique=True, blank=True)
order = models.IntegerField(null=True)

views.py

class ChapterCreate(LoginRequiredMixin, CreateView):
login_url = reverse_lazy('login')
model = Chapter
slug_url_kwarg = 'book_slug'
form_class = ChapterForm
template_name_suffix = '-create'
def get_object(self):
return Book.objects.get(slug=self.kwargs['book_slug'])
def get_context_data(self, **kwargs):
context = super(ChapterCreate, self).get_context_data(**kwargs)
context['book'] = Book.objects.get(slug=self.kwargs['book_slug'])
return context
def form_valid(self, form):
book = self.get_object()
chapter = form.save(commit=False)
chapter.book = book
requested_order = form.cleaned_data['order']
if requested_order == chapter.order:
'''
Reverse the queryset and slice it up to the requested order. 
Add 1 to the chapter orders (chapter.order + 1).
Save them to create a slot for the new chapter.
'''
chapters = course.chapters.order_by("-order")
for l in chapters[:((len(chapters)+1)-requested_order)]:
l.order += 1
print(l.order)
l.save()
try:
chapter.save()
except IntegrityError as e:
raise IntegrityError("Error: {}".format(e))
return super(ChapterCreate, self).form_valid(form)
def dispatch(self, *args, **kwargs):
book = self.get_object()
if not self.request.user.is_authenticated:
messages.info(self.request, 'You need to be logged in to edit a chapter.')
elif book.author != self.request.user:
raise PermissionDenied
return super(ChapterCreate, self).dispatch(*args, **kwargs)

这适用于顺序排序,但失败

  1. 当切片索引变为负数时。
  2. 非顺序排序(当中间有缺失或删除的章节时(。

我错过了什么?有没有更好的方法可以做到这一点?

如果排序是顺序的,你可以使用这样的东西:

# Increment all chapter orders greater or equal to the requested order:
book.chapters.filter(order__gte=requested_order).update(order=F("order") + 1)
# Now just set the order directly on the object:
chapter.order = requested_order
chapter.save()

F 表达式的文档。

由于看起来这对您不起作用,因此您可能需要逐个更新章节:

for chapter_to_update in book.chapters.filter(
order__gte=requested_order
).order_by('-order'):
chapter_to_update.order += 1
chapter_to_update.save()
chapter.order = requested_order
chapter.save()

如果你在一本书中有很多章节,这会很慢。

相关内容

最新更新