2009-09-23 19 views
8

Estoy intentando implementar comprobaciones de seguridad basadas en filas para los modelos Django. La idea es que cuando acceda al administrador de modelos, especifique información adicional que se usa en las consultas de la base de datos para que solo se obtengan las instancias permitidas de la base de datos.Modelos Django: pase información adicional al administrador

Por ejemplo, podemos tener dos modelos: Usuarios y, por ejemplo, Elementos. Cada artículo pertenece a un usuario y el usuario puede estar conectado a muchos elementos. Y que haya algunas restricciones, según las cuales un usuario puede ver o no los Elementos de otro Usuario. Quiero separar este restricciones de otros elementos de consulta y escribir algo como:

items = Item.scoped.forceRule('user1').all() # all items visible for 'user1' 

o

# show all items of 'user2' visible by 'user1' 
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') 

Para lograr esto que hice siguiente:

class SecurityManager(models.Manager): 

    def forceRule(self, onBehalf) : 
     modelSecurityScope = getattr(self.model, 'securityScope', None) 
     if modelSecurityScope : 
      return super(SecurityManager, self).get_query_set().filter(self.model.securityScope(onBehalf)) 
     else : 
      return super(SecurityManager, self).get_query_set() 

    def get_query_set(self) : 
     # 
     # I need to know that 'onBehalf' parameter here 
     # 
     return super(SecurityManager, self).get_query_set() 

class User(models.Model) : 
    username = models.CharField(max_length=32, unique=True) 

class Item(models.Model) : 
    author = models.ForeignKey(User) 
    private = models.BooleanField() 
    name = models.CharField(max_length=32) 

    scoped = SecurityManager() 

    @staticmethod 
    def securityScope(onBehalf) : 
     return Q(author__username__exact = onBehalf) | Q(bookmark__private__exact = False) 

Para ejemplos muestran que funciona bien , pero muere en lo siguiente:

items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*) 
items2 = items[0].author.item_set.all() # (**) 

Ciertamente, items2 está poblado por todos los elementos de 'usuario2', no solo aquellos que conforman la regla. Eso es porque cuando se ejecuta all() SecurityManager.get_query_set() no tiene información sobre el conjunto de restricciones. Aunque podría. Por ejemplo, en forceRule() podría agregar un campo para cada instancia y luego, si pudiera acceder a ese campo desde el administrador, aplicar la regla necesaria.

Entonces, la pregunta es: ¿hay alguna manera de pasar un argumento proporcionado a forceRule() en la declaración (*) al administrador, llamado en la declaración (**).

O bien, otra pregunta: ¿estoy haciendo cosas extrañas que no debería hacer?

Gracias.

+0

Me enfrento al mismo caso de uso también, me pregunto cómo te las arreglaste para evitar esto? ¡Gracias! – ultrajohn

Respuesta

4

De mi lectura de la documentación Creo que hay dos problemas:

  1. El SecurityManager no será utilizada para los objetos relacionados (e instancia de django.db.models.Manager se utilizará en su lugar)
  2. Puede corregir lo anterior, pero la documentación va al gran lengths para especificar que get_query_set() no debe filtrar ninguna fila para las consultas relacionadas.

Sugiero crear una función que tome un QuerySet y aplique el filtro que necesita. Esto se puede usar siempre que obtenga un QS de elementos y desee procesarlos más.

+0

Gracias por la respuesta. 1. Leí la documentación y me sorprendió mucho cuando durante 'items [0] .author.item_set.all()' Django llamó a SecurityManager.get_query_set(). No se los pedí con use_for_related_fields. Pero fue el único gerente para el modelo, tal vez es importante. 2. Sí, lo leí pero sigo pensando que no es mi caso, porque realmente quiero que Django vea no toda la base de datos, sino parte de ella. Probablemente, lo haré de alguna manera como sugirió, pero mi pregunta no es cómo filtrar los datos irrelevantes, sino hacer que este filtrado sea lo más fácil y automático posible. –

Cuestiones relacionadas