Я создаю простой API, используя django-tastypie. Идея заключается в том у меня есть два ресурса:Проблемы с ForeignKey с использованием POST в Django-Tastypie
- Примечание ресурс, представляющий записку, оставленную пользователем. Только пользователь, создавший заметку, может ее редактировать.
- A Комментарий Ресурс. Комментарии могут быть оставлены на любой ноте любым пользователем.
TL; DR: Я не может ограничить Примечание редактирования создателя записки в то же время позволяя любому пользователю комментировать Примечание.
Я использую следующие настройки для проверки подлинности:
class CreatedByEditAuthorization(Authorization):
def is_authorized(self, request, object=None, **kwargs):
return True
def apply_limits(self, request, object_list):
if request and request.method != 'GET' and hasattr(request, 'user'):
return object_list.filter(created_by=request.user)
return object_list
Короче говоря, пользователь разрешен только для редактирования объектов, для которых они равны свойству CREATED_BY (они могут редактировать только объекты, созданные ими) ,
Это связано следующим образом:
class NoteResource(ModelResource):
comments = fields.ToManyField('myapp.api.resources.CommentResource', 'comments', null=True, blank=True)
created_by = fields.ToOneField('account.api.resources.UserResource', 'created_by')
def obj_create(self, bundle, request, **kwargs):
return super(HapResource, self).obj_create(bundle, request, created_by=request.user)
class Meta:
queryset = Note.objects.all()
allowed_methods = ['get', 'put', 'post']
authorization = CreatedByEditAuthorization()
так вот, когда создается объект, я автоматически присоединять текущего пользователя к атрибуту created_by
и связать его с надлежащей авторизации.
A Comment
Ресурс прост и имеет только ForeignKey
до Note
ресурса.
Проблема заключается в следующем: Если пользователь A создает примечание, и пользователь B пытается прокомментировать эту ноту, tastypie отправляет (или имитирует) запрос POST для редактирования этой заметки. Эта попытка отвергается, так как пользователь B не создает заметку, поэтому создание комментария не выполняется.
Вопрос заключается в следующем: Есть ли способ либо:
- Предотвращение tastypie с помощью POST, чтобы создать реверс-отношение к Note ресурса или
- изменения схемы авторизации поэтому Notes можно редактировать только их создателем, но комментарии могут быть созданы вообще?
Заранее благодарим за любые идеи.
Редактировать: У меня есть большой толстый взлом, который может это сделать. Я уверен, что это безопасно, но я не уверен. Я попытаюсь построить некоторые запросы, чтобы убедиться. Вместо того, чтобы использовать fields.ForeignKey
в Comment
относиться к Note
, создать настраиваемое поле:
class SafeForeignKey(fields.ForeignKey):
def build_related_resource(self, value, request=None, related_obj=None, related_name=None):
temp = request.method
if isinstance(value, basestring):
request.method = 'GET'
ret = super(SafeForeignKey, self).build_related_resource(value, request, related_obj, related_name)
request.method = temp
return ret
Каждый раз, когда мы пытаемся построить этот связанный ресурс, мы отмечаем запрос как GET
(так как мы ожидаем, что он должен быть согласован с a SELECT
, а не UPDATE
, который соответствует PUT
или POST
). Это очень уродливое и потенциально опасное, если оно используется неправильно, и я надеюсь на лучшее решение.
Редактировать 2: От чтения источника тастипирования, насколько я могу судить, нет способа фильтровать разрешение по запросу, которое будет фактически отправлено.
Пара вопросов - Вы используете contrib.comments? Вы используете аутентификацию, а также авторизацию? У меня есть то, что похоже на очень похожую настройку (без комментария CommentResource), которая отлично работает при публикации нового комментария к другому объекту пользователя. – JamesO
@JamesO Нет, наши комментарии несколько богаче, чем предоставляет contrib.comments (и есть другие данные, связанные с сообщением, имеющим ту же проблему). В настоящее время мы просто используем встроенную аутентификацию() (т. Е. Все аутентифицируются). –
Вы разместили это как проблему на django-tastypie: https://github.com/toastdriven/django-tastypie/issues? Если он действительно пытается обновить родительскую запись каждый раз, когда вы создаете что-то, связанное с ней, это ближе к ошибке, чем к какой-либо функции. –