Estoy construyendo una API simple usando django-tastypie. La idea es que tengo dos recursos:Problemas con ForeignKey usando POST en Django-Tastypie
- Un Nota recurso que representa una nota dejada por un usuario. Solo el usuario que creó una Nota puede editarla.
- A Comentario recurso. Los comentarios pueden dejarse en cualquier nota de cualquier usuario.
TL; DR: Soy incapaz de limitar la edición de nota al creador de una nota al tiempo que permite a cualquier usuario para comentar en una nota.
estoy usando la siguiente configuración para la autenticación:
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
En pocas palabras, un usuario sólo está autorizado para editar los objetos de los que son iguales a la propiedad created_by (sólo pueden editar los objetos que crearon) .
Esto está relacionado de la siguiente manera:
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()
así que aquí, cuando se crea un objeto, que se conecte automáticamente, el usuario actual al atributo created_by
y vincularlo con la debida autorización.
Un recurso Comment
es simple y solo tiene un ForeignKey
a un recurso Note
.
El problema es este: si el usuario A crea una Nota y el usuario B intenta comentar sobre esa Nota, tastypie envía (o simula) una solicitud POST para editar esa Nota. Ese intento se rechaza ya que el usuario B no creó la Nota, por lo que la creación del comentario falla.
La pregunta es la siguiente: ¿Hay una manera de cualquiera:
- Prevenir tastypie el uso de un POST para crear la inversa relación con la nota de recursos o
- cambiar el esquema de autorización por lo que las Notas solo pueden ser editadas por su creador, ¿pero los comentarios pueden ser creados en general?
Gracias de antemano por cualquier idea.
Editar: Tengo un gran hack gordo que puede lograr esto. Estoy bastante seguro de que es seguro, pero no estoy seguro; Intentaré construir algunas consultas para asegurarme. En lugar de utilizar fields.ForeignKey
en Comment
relacionarse con Note
, se crea un campo personalizado:
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
Cada vez que tratamos de construir este recurso relacionado, marcamos la solicitud como una GET
(ya que esperamos que se puede adaptar a una consulta SELECT
en lugar de UPDATE
que coincide con PUT
o POST
). Esto es realmente feo y potencialmente inseguro si se usa incorrectamente, y espero una mejor solución.
Edit 2: Al leer la fuente de sabrosa, hasta donde puedo decir, no hay forma de filtrar la autorización por la consulta que realmente se enviará.
Un par de preguntas - ¿Estás utilizando contrib.comments? ¿Estás usando autenticación y autorización? Tengo lo que parece ser una configuración muy similar (sin parecer CommentResource) que funciona bien al publicar un nuevo comentario en otro objeto de los usuarios. – JamesO
@JamesO No, nuestros comentarios son algo más ricos que contrib.comments (y hay otros datos asociados con una publicación que está teniendo el mismo problema). Actualmente solo estamos usando la autenticación incorporada() (es decir, todos están autenticados). –
¿Ha publicado esto como un problema en django-tastypie: https://github.com/toastdriven/django-tastypie/issues? Si realmente intenta actualizar un registro principal cada vez que crea algo relacionado con él, eso está más cerca de un error que de una característica. –