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.
Me enfrento al mismo caso de uso también, me pregunto cómo te las arreglaste para evitar esto? ¡Gracias! – ultrajohn