Digamos que tengo un modelo:
class Employee(models.Model): first_name = models.CharField(max_length=40) last_name = models.CharField(max_length=60) salary = models.DecimalField(decimal_places=2)Quiero que cualquiera pueda acceder a first_name y last_name, pero solo quiero que ciertos usuarios puedan leer el salario porque se trata de datos confidenciales.
Y luego quiero restringir la escritura/actualización de salario a un tipo de usuario incluso diferente.
¿Cómo restrinjo la lectura/escritura/actualización del campo según el usuario de la solicitud?
EDITAR:
Esto está en el contexto de la API de GraphQL. Estoy usando grafeno. Me gustaría ver una solución escalable en la función de resolución.
Suponiendo que tienes
employees = graphene.List(EmployeeType) def resolve_employees(self, info, **kwargs): return Employee.objects.all()y
can_view_salary y can_edit_salary Luego, deberá definir EmployeeType con un valor de salary que depende del usuario. Algo como
from graphene_django.types import DjangoObjectType from myapp.models import Employee class EmployeeType(DjangoObjectType): class Meta: model = Employee def resolve_salary(self, info): if info.context.user.has_perm('myapp.can_view_salary'): return self.salary return None Lo importante es que está creando una función de resolve personalizada para el salario que cambia según el valor de un permiso. No necesita crear ningún otro solucionador para first_name y last_name .
Lea primero la documentación. Pero no hay un ejemplo para hacer una actualización.
En resumen, este es el enfoque que puede tomar:
Mutation class MyMutations(graphene.ObjectType): set_employee = SetEmployee.Field()SetEmployee que obtenga el objeto Employee y lo actualice. El campo de salario se ignora para ciertos usuarios. class SetEmployee(graphene.Mutation): class Arguments: id = graphene.ID() first_name = graphene.String() last_name = graphene.String() salary = graphene.String() employee = graphene.Field(lambda: EmployeeType) @classmethod def mutate(cls, root, info, **args): employee_id = args.get('employee_id') # Fetch the employee object by id employee = Employee.objects.get(id=employee_id) first_name = args.get('first_name') last_name = args.get('last_name') salary = args.get('salary') # Update the employee fields from the mutation inputs if first_name: employee.first_name = first_name if last_name: employee.last_name = last_name if salary and info.context.user.has_perm('myapp.can_edit_salary'): employee.salary = salary employee.save() return SetEmployee(employee=employee)Nota: cuando se escribió originalmente esta respuesta, no había un campo Decimal disponible en Graphene Django; evité este problema tomando una cadena como entrada.
Gran respuesta @MarkChackerian. Sin embargo, personalmente, creo que devolver un valor nulo para un campo en acceso no autorizado puede ser ambiguo, por lo que personalmente planteo una excepción del método de resolución como esa:
class UnauthorisedAccessError(GraphQLError): def __init__(self, message, *args, **kwargs): super(UnauthorisedAccessError, self).__init__(message, *args, **kwargs) def resolve_salary(self, info): if info.context.user.has_perm('myapp.can_view_salary'): return self.salary raise UnauthorisedAccessError(message='No permissions to see the salary!')