How to limit field access on a model based on user type on Graphene/Django?

前端 未结 2 1052
暖寄归人
暖寄归人 2021-02-02 16:30

Let\'s say I have a model:

class Employee(models.Model):
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=60)
    sal         


        
相关标签:
2条回答
  • 2021-02-02 17:01

    Great response @MarkChackerian. However personally, I believe that returning a null value for a field on unauthorised access can be ambiguous, so I personally raise an exception from resolve method like that:

    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!')
    
    0 讨论(0)
  • 2021-02-02 17:19

    QUERIES

    Assuming that you have

    1. a query defined like

      employees = graphene.List(EmployeeType)

    2. a resolver for the query like

      def resolve_employees(self, info, **kwargs): return Employee.objects.all()

    and

    1. permissions on your Employee model called can_view_salary and can_edit_salary

    Then you'll need to define the EmployeeType with a value of salary that is dependent on the user. Something like

    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
    

    The important takeaway is that you're creating a custom resolve function for the salary that is switching based on the value of a permission. You don't need to create any other resolvers for first_name and last_name.




    MUTATIONS

    Read the documentation first. But there isn't an example for doing an update.

    In brief, here's the approach that you can take:

    1. Create a method to set the employee in your Mutation method

      class MyMutations(graphene.ObjectType): set_employee = SetEmployee.Field()

    2. Create a method for SetEmployee that gets the Employee object and updates it. The salary field is ignored for certain users. Note again that I am ignoring the Decimal issue by taking a string as an input.

      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)
      
    0 讨论(0)
提交回复
热议问题