Как обновить поле manytomany в Django?

Вот пример:

Если у меня есть эти классы

class Author(models.Model):
    name = models.CharField(max_length=45)

class Book(models.Model):
    name = models.CharField(max_length=45)
    authors = models.ManyToManyField(Author)

В базе данных у меня есть один автор с именем "Джордж" и еще один с именем "Georfe". Последняя ошибка. Итак, я хочу, чтобы в каждой книге, в которой "Геофен", как один из его авторов, заменил ее автор "Джордж".

В SQL действительно легко сделать. Если id "George" = 3 и id "Georfe" = 7, а имя таблицы отношений - "author_book":

UPDATE author_book SET id=3 WHERE id=7;

Возможно ли это сделать с помощью Django ORM?

Я нашел способ сделать это: я петлю через все связанные книги Ошибочного автора и делаю:

book.authors.add(Author.objects.get(id=3))
book.authors.remove(Author.objects.get(id=7))

Но я не считаю это решение действительно элегантным и эффективным. Есть ли решение без цикла?

Ответы

Ответ 1

Примечание.. Этот код удалит плохого автора "georfe", а также обновит книги, чтобы указать на правильного автора. Если вы не хотите этого делать, используйте .remove() в качестве ответа @jcdyer.

Можете ли вы сделать что-то подобное?

george_author = Author.objects.get(name="George")
for book in Book.objects.filter(authors__name="Georfe"):
    book.authors.add(george_author.id)
    book.authors.filter(name="Georfe").delete()

Я подозреваю, что это было бы проще, если бы у вас была явная таблица, соединяющая две модели (с аргументом "через" ), в этом случае у вас был бы доступ к таблице отношений напрямую и мог бы просто сделать .update(id=george_author.id) на нем.

Ответ 2

С помощью автоматической сгенерированной таблицы вы можете сделать двухэтапную вставку и удаление, что приятно для читаемости.

george = Author.objects.get(name='George')
georfe = Author.objects.get(name='Georfe')

book.authors.add(george)
book.authors.remove(georfe)
assert george in book.authors

Если у вас есть явно определенная таблица (authors = models.ManyToManyField(Author, via = BookAuthors), вы можете явно изменить отношение на BookAuthor. Не известно, что эта модель уже существует, она генерируется django Обычно вы должны создавать явную сквозную модель, если у вас есть дополнительные данные, которые вы хотите сохранить (например, главы, которые автор написал в книге с несколькими авторами).

# This line is only needed without a custom through model.
BookAuthor = Book.authors.through
book_author = BookAuthor.objects.get(author=georfe, book=great_american_novel)
book_author.author = george
book_author.save()
assert george in book.authors