Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: expected string or bytes-like object, when removing an image in Django's UpdateView #98

Closed
sunnyville opened this issue May 24, 2017 · 11 comments
Assignees

Comments

@sunnyville
Copy link

sunnyville commented May 24, 2017

Hello,

I'm using Cloudinary in my Django application, and everything is working fine. Except in my UpdateVIew, when a user checks 'clear' to remove an uploaded image and submit the form this error is shown:

TypeError: expected string or bytes-like object

The error page in the browser also shows these highlighted messages:

...\lib\site-packages\cloudinary\models.py in to_python
return self.parse_cloudinary_resource(value) ...

...\lib\site-packages\cloudinary\models.py in parse_cloudinary_resource
m = re.match(CLOUDINARY_FIELD_DB_RE, value) ...

...\AppData\Local\Programs\Python\Python36-32\lib\re.py in match
return _compile(pattern, flags).match(string)

These are what my model, view and form look like:

models.py:

class Item(models.Model):
    name = models.CharField(max_length=255)
    image1 = CloudinaryField('image', blank=True, null=True)

views.py

class ItemUpdateView(LoginRequiredMixin, UpdateView):
    model = models.Item
    form_class = forms.ItemForm

forms.py

class ItemForm(forms.ModelForm):
    image1 = CloudinaryFileField(
                required=False,
                options = {'crop': 'limit', 'width': 546, 'height': 1000,})
    class Meta:
        model = models.Item
        fields = ("image1", "name")

I think Cloudinary is still expecting something when the field's value is empty. I've used required=False because I want the image to be optional as that is how it is in my model. I have looked at the docs and searched the web and I just can't figure out how to fix this.

Thanks.

@tocker
Copy link
Contributor

tocker commented Sep 10, 2017

The error indicates that the value passed to to_python is not a string.

We may be missing a check for "self":

if isinstance(value, CloudinaryField):
            return value

Can you please debug and check the type and value of the value argument passed to to_python?

@twoblokeswithapostie
Copy link

I'm hitting this issue. The value sent is Boolean False and match expects a string, so it fails.

The exception is thrown in this line:

return _compile(pattern, flags).match(string)

These are the variable values:

flags | 0
pattern | '(?:(?P<resource_type>image|raw|video)/(?Pupload|private|authenticated)/)?(?:v(?P\d+)/)?(?P<public_id>.*?)(\.(?P[^.]+))?$'
string | False

This happens when you click on "Clear" checkbox inside a Django's ModelForm. It's a default widget for deleting a FileField value.

Here's a full traceback:

Traceback:

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/core/handlers/base.py" in _legacy_get_response
249. response = self._get_response(request)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
23. return view_func(request, *args, **kwargs)

File "/Users/mariogudelj/projects/cp/console/views.py" in console_views_wrapper
91. return function(*args, **kwargs)

File "/Users/mariogudelj/projects/cp/console/views.py" in order_edit
1012. if product_edit_form.is_valid() and quote_edit_form.is_valid():

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/forms/forms.py" in is_valid
183. return self.is_bound and not self.errors

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/forms/forms.py" in errors
175. self.full_clean()

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/forms/forms.py" in full_clean
386. self._post_clean()

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/forms/models.py" in _post_clean
413. self.instance.full_clean(exclude=exclude, validate_unique=False)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/db/models/base.py" in full_clean
1227. self.clean_fields(exclude=exclude)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/db/models/base.py" in clean_fields
1269. setattr(self, f.attname, f.clean(raw_value, self))

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/django/db/models/fields/init.py" in clean
605. value = self.to_python(value)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/cloudinary/models.py" in to_python
74. return self.parse_cloudinary_resource(value)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/site-packages/cloudinary/models.py" in parse_cloudinary_resource
50. m = re.match(CLOUDINARY_FIELD_DB_RE, value)

File "/Users/mariogudelj/Envs/cp/lib/python2.7/re.py" in match
141. return _compile(pattern, flags).match(string)

Exception Type: TypeError at /console/order-edit/2525308/
Exception Value: expected string or buffer

@twoblokeswithapostie
Copy link

Can I bump this issue? I'm not sure how to fix it, but I think that to_python method inside CloudinaryField needs to be patched to return value if the type is boolean. Cheers, m

@macarena
Copy link

Any solution?

@macarena
Copy link

macarena commented Nov 19, 2017

I've fixed it changing to_python method.
The value passed em deleting de image is False, not None. So I just added this possibility on the method.

def to_python(self, value):
        if isinstance(value, CloudinaryResource):
            return value
        elif isinstance(value, UploadedFile):
            return value
        elif value is None or value is False:
            return value
        else:
            return self.parse_cloudinary_resource(value)

The problem is the image is kept on cloudinary, but I think is simple to just add the api in here.
I guess i still need to figure out which scenario was meant to correspond with the None value.

@tocker
Copy link
Contributor

tocker commented Dec 4, 2017

@macarena that the image is kept in Cloudinary shouldn't be a problem, yet you can always remove it manually or as part of the application process.
From a simple test I did your suggested solution works (or at least doesn't break...)
If this is a viable solution I'll modify the code.

@sunnyville @twoblokeswithapostie Comments are welcome!

@twoblokeswithapostie
Copy link

@macarena nailed it. That is the solution indeed.

@jakhax
Copy link

jakhax commented Jul 2, 2018

@macarena solution works very well indeed, @tocker please consider fixing this issue.

@yakirp
Copy link

yakirp commented Jul 7, 2018

Hey @macarena,
It's on our roadmap, we will update.

Thanks,
--Yakir

@roeeba roeeba assigned const-cloudinary and unassigned tocker Jan 7, 2019
@goodtune
Copy link
Contributor

As a workaround, I've implemented the following on my form.

class UserPhotoForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ("photo",)

    def clean_photo(self):
        data = self.cleaned_data.get("photo")
        if data is False:
            data = None
        return data

@dimplemathewkc
Copy link

I remove the migrations folder and then python manage.py makemigrations app_name. It worked for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants