如何在graphene_django中隐藏/排除请求实体的某些外键字段?

Mos*_*imi 5 python django graphql graphene-django

我已阅读有关如何在这些链接中排除(隐藏)django 和 graphene_django 中的某些字段的信息:

想象一下,我们有以下Post模型,它具有模型的外键User。

应用程序/帖子/models.py

from django.db import models
from apps.users.models import User

class Post(models.Model):
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        null=False
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
    )

    title = models.TextField(
        null=False,
        max_length=100,
    )

    content = models.TextField(
        null=False,
    )

    def __str__(self):
        return self.title
Run Code Online (Sandbox Code Playgroud)

应用程序/用户/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser, models.Model):
    phone_no = models.CharField(
        blank=True,
        null=True,
        default="",
        max_length=10,
        verbose_name="Phone Number",
    )

    avatar = models.ImageField(
        null=True,
        upload_to='static',
    )

    USERNAME_FIELD = "username"
    EMAIL_FIELD = "email"

    def __str__(self):
        return self.username

Run Code Online (Sandbox Code Playgroud)

我尝试了以下操作,但没有按预期工作:

应用程序/帖子/schema.py

import graphene
from graphene import Mutation, InputObjectType, ObjectType
from graphene_django.types import DjangoObjectType

from .models import Post


class PostType(DjangoObjectType):
    class Meta:
        model = Post
        exclude_fields = [
            'created_at', #it worked
            'author.password', #the way I tried to hide the foreign key field
            
        ]

class Query(ObjectType):
    posts = graphene.List(
        PostType
    )

    def resolve_posts(self, info):
        #TODO: pagination
        return Post.objects.all()
Run Code Online (Sandbox Code Playgroud)

截屏:

失眠截图

如何在 graphql 模型类型中隐藏它的某些字段(如上例中的作者密码)?

JPG*_*JPG 5

从评论中我了解到你有一个UserType班级

exclude您可以在元中使用该选项,

class UserType(DjangoObjectType):
    class Meta:
        model = User
        exclude = ('password',)
Run Code Online (Sandbox Code Playgroud)

更新

您还可以使用自定义解析器来检查请求的实体

class UserType(DjangoObjectType):
    password = graphene.String()

    def resolve_password(self, info):
        requested_user = info.context.user
        if requested_user.email in ['admin@test.com', 'ceo@test.com']:
            return self.password
        return None

    class Meta:
        model = User
        fields = '__all__'
Run Code Online (Sandbox Code Playgroud)


Sag*_*ari 2

这只是在解析查询字段之前检查权限的答案。(所以,不是原始问题的答案)

像这样的东西会起作用。


def permission_check_my_field(func):
    @wraps(func)
    def wrapper(self,info,**kwargs):
        user=info.context.user
        if (......) # permit condition here
           return func(self, info,**kwargs)
        else:
            return None
    return wrapper

class  Query(graphene.ObjectType):
    my_field = graphene.Field(...) # or graphene.List or .....
    
    @permission_check_my_field
    def resolve_my_field(......)
      # do your normal work

Run Code Online (Sandbox Code Playgroud)

更新。

如果用户数据足以检查该字段是否可访问(如其他答案),则上述代码有效。但是,如果您需要检查用户是否已被授予访问该字段的某些权限,那么您需要这样做:


def permission_check_in_query(perm):
    def wrapped_decorator(func):
        @wraps(func)
        def wrapper(self,info,**kwargs):
            user=info.context.user
            if user.has_perm(perm) # check if the user has privilege
                return func(self, info,**kwargs)
            else:
                return None 
                # All fields are not nullable, so  `return None' might throw error. You can pass `what you need to return` in decorator argument and use it here , to avoid this.   
        return wrapper
    return wrapped_decorator

class  Query(graphene.ObjectType):
    my_field = graphene.Field(...) # or graphene.List or .....
    
    @permission_check_in_query('model.access_my_field') # your permission code 
    # learn django permissions if you are not sure what it is
    # doesn't have to be django_permission, can be any argument like 'is_it_a_superuser' that you will use to check user privilege. Modify decorator code accordingly
    def resolve_my_field(......)
      # do your normal work

Run Code Online (Sandbox Code Playgroud)

这样做,您可以重用任何字段和任何权限。@permission_check_in_query(your arguments)只需在解析之前需要进行权限检查的任何字段上方添加装饰器即可。

TLDR:这个答案与有关 API 接受和返回的数据类型的其他答案类似。它只是提供可重用性和权限检查。