strawberry-django icon indicating copy to clipboard operation
strawberry-django copied to clipboard

TypeError: No type defined for 'ImageField'

Open holtergram opened this issue 3 years ago • 10 comments

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!

holtergram avatar Apr 14 '21 08:04 holtergram

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.

la4de avatar Apr 14 '21 15:04 la4de

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?

holtergram avatar Apr 15 '21 17:04 holtergram

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

patrick91 avatar Apr 15 '21 18:04 patrick91

@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?

holtergram avatar Apr 15 '21 18:04 holtergram

@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 avatar Apr 15 '21 20:04 la4de

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

la4de avatar May 12 '21 06:05 la4de

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

la4de avatar May 18 '21 16:05 la4de

@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.

holtergram avatar May 19 '21 12:05 holtergram

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

la4de avatar May 19 '21 13:05 la4de

@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.

la4de avatar May 21 '21 05:05 la4de

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

mnogokotin avatar Dec 26 '22 10:12 mnogokotin

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)

mnogokotin avatar Dec 26 '22 12:12 mnogokotin

This should be fixed in v0.10.0

bellini666 avatar Jul 05 '23 15:07 bellini666