strawberry-graphql / strawberry-django

Strawberry GraphQL Django extension
https://strawberry.rocks/docs/django
MIT License
415 stars 120 forks source link

TypeError: No type defined for 'ImageField' #22

Closed holtergram closed 1 year ago

holtergram commented 3 years ago

Hey, in my User model I've got this field:

def user_directory_path(instance, filename):
    filename, ext = os.path.splitext(filename)
    return os.path.join(
        f'profile_pictures/{instance.uuid}/',
        f'{uuid.uuid4()}{ext}'
    )

...

profile_picture = models.ImageField(
        verbose_name=_('profile picture'),
        upload_to=user_directory_path,
        blank=True,
    )

and I guess I'm doing something wrong because I can't define the type of the ImageField.

@types.register
@strawberry_django.type(User, types=types)
class User:
    profile_picture: any
    profilePicture: any

Whatever I try to define it keeps raising the error. What am I missing? Also: Does this package support all kind of types like "PhoneNumberField" or "versatileimagefield"? Do I have to define these "special" fields alsways as any?

Thanks!

Upvote & Fund

Fund with Polar

la4de commented 3 years ago

strawberry-graphql-library does not support ImageField yet as you can see from here: https://github.com/strawberry-graphql/strawberry-graphql-django/blob/main/strawberry_django/types.py#L24

You need to define the resolver yourself for profile_picture. Something like this should do the job

@types.register
# NOTE: profile_picture has to be excluded from fields argument
@strawberry_django.type(User, fields=['username'], types=types)
class User:
    @strawberry_django.field
    def profile_picture(self) -> str:
        return self.profile_picture.url

UPDATE: Sample code updated. Previous version did not work because fields parameter was not given, which means that strawberry django tried to convert all fields of given model. We are planning to drop fields parameter from the next API version and define all fields in class body. See #20.

holtergram commented 3 years ago
lib/python3.9/site-packages/strawberry_django/types.py", line 136, in get_model_fields
    for field in model._meta.get_fields():
AttributeError: type object 'User' has no attribute '_meta'

Is having a Meta class in the model mandatory?

patrick91 commented 3 years ago

@2malh any django model has a _meta, maybe in this case you User class is not a django model?

holtergram commented 3 years ago

@2malh any django model has a _meta, maybe in this case you User class is not a django model?

Ahh, well since it's recommended to use a custom user model I've defined it like this class User(AbstractUser): In that case AbstractUser and AbstractBaseUser should definitely be added to the list, right?

la4de commented 3 years ago

@2malh, types can be generated only from models, not from abstract classes. You can inherit your own model from abstract class. Django provides nice documentation with examples for that. https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#substituting-a-custom-user-model

Currently unsupported django fields are FileField, ImageField and JsonFields. You can use them by defining your own resolvers and get them work in that way. See my previous comment.

la4de commented 3 years ago

ImageField and FileField should work now with code in features/class-api branch. Feel free to try.

la4de commented 3 years ago

This has been implemented in pull request #30 and will be part of v0.2 release.

holtergram commented 3 years ago

@la4de thanks for the implementation. It seems to throw an error if no file is uploaded

The 'picture' attribute has no file associated with it. First: I suggest to rephrase the message to "The field '{field_name}' on model '{model_name}' has no image associated with it / is empty." but what's even more helpful: not throwing an error and return None/Null and set that as default to not break the query if "blank=true" is set on the model.

To elaborater on this issue: This doesn't throw an error:

{
  users {
    picture {
      name
    }
  }
}

but querying for any other attribute (size, height, path, url etc.) does result in an error.

I haven't checked FileField as I'm not using it atm but I guess the same is true for this field.

la4de commented 3 years ago

Thanks for reporting this. It seems that we may need to add special resolver for that field type.

la4de commented 3 years ago

@la4de thanks for the implementation. It seems to throw an error if no file is uploaded

The 'picture' attribute has no file associated with it. First: I suggest to rephrase the message to "The field '{field_name}' on model '{model_name}' has no image associated with it / is empty." but what's even more helpful: not throwing an error and return None/Null and set that as default to not break the query if "blank=true" is set on the model.

I think the best workaround is to define resolver to the field which returns None if picture is not set.

def resolve_picture(root):
    if not root.picture:
        return None
    return root.picture

@strawberry_django.type(models.User)
class User:
    picture: auto = strawberry_django.field(resolver=resolve_picture)

Please let us know if this works for you.

I think the proper solution would be to add default resolver or special field to DjangoFileType and DjangoImageType types. Need to think how to implement that.

mnogokotin commented 1 year ago

any fix for this? ) same issue: https://github.com/strawberry-graphql/strawberry-graphql-django/issues/58

mnogokotin commented 1 year ago
def resolve_picture(root):
    if not root.picture:
        return None
    return root.picture

@strawberry_django.type(models.User)
class User:
    picture: auto = strawberry_django.field(resolver=resolve_picture)

Please let us know if this works for you.

I got error "Unexpected type 'auto'". I replaced auto with Optional[DjangoFileType] and it works for me:

from strawberry_django.fields.types import DjangoFileType

@strawberry_django.type(models.User)
class User:
    picture: Optional[DjangoFileType] = strawberry_django.field(resolver=resolve_picture)
bellini666 commented 1 year ago

This should be fixed in v0.10.0