#django #sqlite #django-models #transactions #many-to-many
#django #sqlite #django-модели #транзакции #многие ко многим
Вопрос:
У меня есть пара связанных моделей, которые выглядят примерно так:
class Book(models.Model):
title = models.TextField()
class Author(models.Model):
"""
>>> b = Book(title='some title')
>>> b.save()
>>> a = Author(name='some name')
>>> a.save()
>>> a.books.add(b)
>>> b in a.books.all()
True
"""
name = models.TextField()
books = models.ManyToManyField(Book)
Эта версия является упрощением моего производственного приложения, но тот же тест в рабочей среде завершается неудачей — a.books.all () возвращает пустой список, даже после того, как я выполняю a.books.add (b).
Я заглянул в базу данных (sqlite), и в таблице объединения определенно была создана новая запись, book_author. Я также пытался вызвать transaction.commit() и connection.close(), чтобы попытаться обновить представление базы данных. Никакой радости. Любые указания на то, какие вещи могут вызывать странное поведение в процессе производства, будут с благодарностью приняты.
Одна из моих мыслей заключалась в том, что это как-то связано с третьей связанной моделью, для которой я вручную указал сквозную таблицу, что-то вроде этого:
class Genre(models.Model):
desc = models.TextField()
books = models.ManyToManyField(Book, through='BookGenres')
class BookGenres(models.Model):
book = models.ForeignKey(Book)
genre = models.ForeignKey(Genre)
Однако добавление этого в тестовое приложение ничего не нарушает… На что еще мне следует обратить внимание?
[правка 11/5] еще более странное поведение, следуя совету Дэниела в комментариях (спасибо за попытку! 🙂
Еще более странное поведение:
>>>a.books.all()
[]
>>>a.books.filter(pk=b.id)
[]
>>>a.books.filter(pk=b.id).count()
1
>>>len(a.books.filter(pk=b.id))
0
Как я уже сказал, мои «реальные» модели более сложные, и я не смог воспроизвести это поведение в упрощенных тестах, но любые идеи о том, на что обратить внимание, были бы с благодарностью оценены.
Ответ №1:
Я не уверен, что in
оператор обязательно работает в наборах запросов. Не забывайте, что экземпляры модели Django не имеют идентификаторов, поэтому два объекта, загруженные из базы данных в ходе двух отдельных операций, могут иметь разные внутренние идентификаторы, даже если у них одинаковый pk.
Я бы явно запросил элемент, который вы ожидаете :
>>> a.books.add(b)
>>> a.books.filter(pk=b.pk).count()
1
Я бы также добавил, что я не вижу смысла в этом тестировании. Операции с моделью Django очень хорошо охвачены его собственным набором тестов — вам следует зарезервировать свои модульные тесты для вашей собственной бизнес-логики.
Комментарии:
1. согласовано — объекты, представляющие один и тот же элемент БД, могут иметь разные внутренние идентификаторы python, но сравниваются одинаково, потому что эквалайзер работает при сравнении pk
2. и я бы не писал тесты для низкоуровневых операций модели django, если бы они вели себя так, как должны были!