I have read about how to exclude (hide) certain fields in django and graphene_django in these Links:
Imagine that we have the following Post
model which has foreign key to the User
model.
apps/posts/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
apps/users/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
I tried the following but it doesn't work as expected:
apps/posts/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()
Screenshot:
How can I hide certain fields of it (like author's password in the above example) in graphql model Types?
From the comments, I have understood that you have a UserType
class
You can use the exclude
option in the meta as,
class UserType(DjangoObjectType):
class Meta:
model = User
exclude = ('password',)
You can also use a custom resolver to check the requested entity
class UserType(DjangoObjectType):
password = graphene.String()
def resolve_password(self, info):
requested_user = info.context.user
if requested_user.email in ['[email protected]', '[email protected]']:
return self.password
return None
class Meta:
model = User
fields = '__all__'
This is answer only for checking permissions before resolving query field. (So, not an answer to original question)
Something like this would work.
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
Update.
Above code works if the user data is enough to check if the field is accessible (like the other answer). However, if you need to check whether or not user has been granted some permission to access that field, then you need to do like this:
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
Doing this, you can reuse for any field and any permission. Just add the decorator @permission_check_in_query(your arguments)
above any field that needs to be permission-checked before being resolved.
TLDR: This answer is similar to other answer regarding the type of data that API accepts and returns. It just offers reusability and permission check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With