Вставка объекта с ManyToMany в Django - PullRequest
1 голос
/ 07 апреля 2009

У меня есть блоговое приложение с историями и категориями:

class Category(models.Model):
    ...
class Story(models.Model):
    categories = models.ManyToManyField(Category)
    ...

Теперь я знаю, что при сохранении нового экземпляра модели с полем «многие ко многим» возникают проблемы, поскольку объект еще не находится в базе данных. Эта проблема обычно проявляется при отправке формы, которую можно аккуратно обойти с помощью story_form.save(commit=False). А как насчет ситуации, когда нет форм, о которых можно говорить? В моем случае я хочу создать API для приема удаленных заявок. Поскольку мне нравится JSON, и многие другие сообщения в нашей компании находятся в JSON (включая исходящие сообщения с этого сервера), я бы хотел получить следующее:

{ "operation": "INSERT",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

и реализовать фабрику, которая преобразует значения в экземпляры. Но я бы хотел, чтобы фабрика была максимально агностичной к типу операций. Итак:

{ "operation": "UPDATE",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

также должен быть преобразован таким же образом, за исключением того, что INSERT игнорирует id, а UPDATE получает уже существующий экземпляр и переопределяет его. (Удаленный отправитель прослушивает фид, который, помимо прочего, дает ему объекты категории для кэширования, поэтому он может и должен ссылаться на них по id, но он не имеет прямой связи с базой данных.)

Мой реальный вопрос: что проще всего сделать, чтобы надувать экземпляр объекта модели Django, к которому подключен ManyToManyManager. Насколько я понимаю, любая вставка объекта с полем «многие ко многим» потребует двух попаданий в базу данных, просто потому, что сначала необходимо получить новый идентификатор. Но мое нынешнее неловкое решение - сохранить объект сразу и пометить его как скрытый, чтобы функции в дальнейшем могли поиграть с ним и сохранить его как нечто более значимое. Похоже, что на один шаг вверх будет переопределено save, чтобы объекты без идентификаторов сохранялись один раз, копировали какое-либо поле прокси в categories, а затем сохраняли снова. Лучше всего будет какой-нибудь надежный объект менеджера, который избавит меня от проблем. Что вы рекомендуете?

Ответы [ 2 ]

3 голосов
/ 07 апреля 2009

"Насколько я понимаю, любая вставка объекта с полем" многие ко многим "потребует двух попаданий в базу данных ..."

И что?

Микроуправление каждым отдельным доступом к базе данных, как правило, не стоит всех думать. Сделайте самое простое и очевидное, чтобы Django мог оптимизировать кеш для вас.

В производительности вашего приложения - как правило - преобладает медленная загрузка в браузер и все файлы JPEGS, CSS и другой статический контент, являющийся частью вашей страницы.

Время, затрачиваемое на умопомрачительные размышления о том, как создать два Первичных ключа (для отношений «многие ко многим») без двух обращений к базе данных, не принесет больших результатов. Два ПК - это обычно два доступа к базе данных.


Редактировать

"... засоряет базу данных при ошибке ..."

У Django есть транзакции. См. http://docs.djangoproject.com/en/dev/topics/db/transactions/#managing-database-transactions. Использование декоратора @transaction.commit_manually.

«вызывает проверку, которая должна произойти позже»

Не имеет смысла - обновите ваш вопрос, чтобы объяснить это.

2 голосов
/ 07 апреля 2009

Я прокомментировал пост С. Лотта, что я считаю его ответ лучшим. Он прав: если цель состоит в том, чтобы просто избежать двух попаданий в базу данных, то вас ждет мир ненужной боли.

Однако, читая вашу ссылку на ModelForm, если вы ищете решение, позволяющее каким-то образом отложить официальное сохранение, вы можете взглянуть на функцию save_instance() в forms.models. Внутренняя функция save_m2m - это то, как отложенное сохранение «многие ко многим» выполняется для форм. Реализация чего-либо для моделей без форм в основном будет следовать тому же принципу.

Сказав это, и возвращаясь к посту С. Лотта, случай ModelForm и фактической Model несколько отличается. Поскольку формы предоставляют только «безопасный» набор данных для редактирования в браузере («безопасный», поскольку он каким-то образом фильтруется или исключает критические поля, которые пользователь не должен редактировать), это разумное предположение о кому-то может понадобиться добавить важную информацию в модель на основе форм перед сохранением. Вот почему у Джанго есть commit=False.

Это ожидание падает для случаев, когда вы непосредственно создаете экземпляры моделей. Здесь у вас есть программный доступ к API модели, поэтому вы, вероятно, обнаружите, что использование этого API напрямую проще в обслуживании и менее подвержено ошибкам, чем через обобщенную косвенную адресацию. Я могу понять, почему вы представляете концепцию фабрики, но в этом случае вы можете обнаружить, что попытка создать пуленепробиваемое обобщение для всех типов моделей является сложностью, которая просто не стоит этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...