2014-12-26 2 views
1

У меня есть две модели в Django:Сохранение двух новых связанных объектов в одном запросе

class Thread(models.Model): 
    entity = models.ForeignKey(Entity, null=True, blank=True) 
    ... 

class ThreadMessage(models.Model): 
    thread = models.ForeignKey(Thread, related_name='messages') 
    author = models.ForeignKey(User) 
    ... 

Теперь клиент хочет, чтобы создать новую тему с первым сообщением в нем. Сначала нужно создать POST /threads, чтобы создать новый поток и узнать его id, а затем сделать POST /messages, передав найденный идентификатор в поле thread.

Я имею в виду, если это разумно и возможно сделать все это в одном запросе от Ember, как:

POST /messages 
{"message": {"text": "text", ...}, 
"thread": {"entity": 1}} 

И ответ будет:

{"message": {"text": "text", "id": 5678, "thread": 1234, ...}, 
"thread": {"entitity": 1, "id": 1234, ...}} 
+0

Я думаю, что эти сообщения будут отвечать на ваш вопрос: http://stackoverflow.com/a/26823614/4322950, ​​однако это будет означать, что вы правильно относитесь к формату запроса ember в Django. Если обратите внимание на то, что у вас есть варианты с store.push и store.pushpayload с ответом пользовательского вызова ajax. – MrVinz

ответ

4

Да, это вполне разумно.

Люди, похоже, интерпретируют REST в очень странном и в значительной степени неосведомленном виде. Беглый просмотр HTTP RFC 7231 для POST и PUT подтвердит, что вы на твердой почве.

Представление ресурсов может представлять НИЧЕГО. Главное - сохранить семантику операций REST. Таким образом, PUT может использоваться как для операций CREATE, так и REPLACE (я склонен думать, что PUT является REPLACE, а не UPDATE, поскольку REPLACE ближе к идемпотентной семантике, чем UPDATE).

A PUT к конечной точке, где поддерживается, должен принимать любое представление, возвращаемое GET. POST может делать буквально все, что вам нужно, поскольку оно не нуждается в поддержке идемпотентной семантики.

HTTP и REST предназначены и предназначены для поддержки представлений ресурсов, которые могут перекрывать другие ресурсы, и RFC явно говорит об этом. Вы делаете это все время, выполняя GET на конечной точке коллекции.

Вы не нарушаете REST, имея поток, содержащий дочернее сообщение в одном запросе, и IMO, который является очень допустимым прецедентом использования для правильной ссылочной целостности на сервере. Каждый раз, когда требуется семантика транзакции, POST или PUT отлично подходят для создания графика объектов на сервере в одном запросе. Это действительно просто, если вы можете ПОЛУЧИТЬ его в одном запросе, вы должны иметь возможность ОТКЛЮЧИТЬ его в одном запросе, поэтому тщательно подумайте о своих URL-адресах и параметрах.

Например, вы можете иметь нить конечную точку, которая возвращает все сообщения, и что конечная точка может поддерживать параметр, чтобы просто вернуть некоторое подмножество информации /api/threads?include=hasRead, которая возвращает только id и hasRead для каждого сообщения в потоке, или, возможно, только некоторые диапазон «страниц». Затем вы можете использовать PUT, используя ту же конечную точку и параметры, и просто обновите свойство hasRead навалом.

Любой, кто повесил трубку, вероятно, никогда не рассматривал элементы управления доступом. Контроль доступа требует другого представления ресурса от одного пользователя к другому в зависимости от того, к чему им разрешен доступ. Это другое представление ресурса передается в заголовках HTTP-заголовков и/или в URL-адресе запроса; снова REST не прерывается путем добавления или перекрытия ресурсов.

Итак, вперед и создайте минимальный граф объектов, которые вам нужны, и либо PUT, либо POST их. Я использую V4 UUID, поэтому клиенты могут сами назначать ID (и, следовательно, конечные точки ресурса), и это позволяет мне использовать PUT для создания и замены подобных действий и связывания сложных графиков объектов без клиента. < -> проблемы с отображением идентификаторов сервера.

+0

Спасибо за ответ. Я согласен с вашими аргументами. Я подтвердил ваш ответ, но не буду его принимать, поскольку этот вопрос выглядит спорным. Спасибо за идею с UUID, хотя у меня есть целые идентификаторы. – warvariuc

+0

Я также использую Ember Data для сериализации нескольких объектов в ответ. Ember Data из коробки поддерживает встроенные записи с EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html, поэтому я не считаю это особенно спорным или «нарушающим Ember», как утверждают другие –

+0

Мне нравится ботинок, потому что он включает в себя каждый связанный рекордер только один раз. Мы уже используем боковое загрузку, переключается на встроенные записи - единственное решение? – warvariuc

-2

То, что вы пытаетесь сделать будет нарушать концепцию REST и EmberJS.

Если у вас есть два отдельных API, you should make two REST calls.

Сначала сохраните модель родительского thread, после успешного возвращения спасти ребенок message. Затем используйте addObject, чтобы отразить изменения в просмотрах.

Это лучший способ. Не пытайтесь оптимизировать, сокращая здесь вызовы API и прерывая REST.

+0

Это не просто оптимизация. Если что-то случится с сетью, я могу закончить с потерянными потоками. – warvariuc

+0

@warvariuc использовать откат в таком случае, чтобы удалить родителя :) – Sushant

+0

Вы имеете в виду на стороне сервера? Это невозможно, транзакция работает в рамках одного запроса. На клиенте? \ – warvariuc