method object is not JSON serializable

pri picture pri · Dec 28, 2017 · Viewed 13k times · Source

I am using ajax to refresh the cart items when cart item is removed. It works well, if i don't response object with image otherwise I get an error method object is not JSON serializable. If i use model_to_dict for the image part, i get an error 'function' object has no attribute '_meta'.

here is the code

def cart_detail_api_view(request):
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    products = [{
            "id": x.id,
            "url": x.get_absolute_url(),
            "name": x.name,
            "price": x.price,
            "image": x.first_image
            }
            for x in cart_obj.furnitures.all()]
    cart_data  = {"products": products, "subtotal": cart_obj.sub_total, "total": cart_obj.total}
    return JsonResponse(cart_data)

class Furniture(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    manufacturer = models.ForeignKey(Manufacturer, blank=True, null=True)
    slug = models.SlugField(max_length=200, unique=True)

    def __str__(self):
        return self.name

    def first_image(self):
        """
        Return first image of the furniture otherwise default image
        """
        if self.furniture_pics:
            return self.furniture_pics.first()
        return '/static/img/4niture.jpg'

class Cart(models.Model):
    user = models.ForeignKey(User, null=True, blank=True)
    furnitures = models.ManyToManyField(Furniture, blank=True)

I get 'function' object has no attribute '_meta' error while wrapping x.first_image to model_to_dict

How do i resolve such issue?

UPDATED

class FurniturePic(models.Model):
    """
    Represents furniture picture
    """
    furniture = models.ForeignKey(Furniture, related_name='furniture_pics')
    url = models.ImageField(upload_to=upload_image_path)

Answer

xyres picture xyres · Dec 28, 2017

The problem, as you know, is at :

"image": x.first_image

first_image is a function, so it can't be converted to JSON. What you want to do is serialize the value returned by first_image. So, for that, you need to call this function:

"image": x.first_image() # note the brackets

Additionally, I also noticed another issue, at:

return self.furniture_pics.first() # will return the image object; will cause error

So, you'll have to change that to:

return self.furniture_pics.first().url # will return the url of the image

Update:

self.furniture_pics.first().url will return FurniturePic.url which is an ImageField. You need the url of that picture for serialization. You'd have to do this:

return self.furniture_pics.first().url.url # call url of `url`

As you can see, this is getting confusing. I'd suggest changing the FurniturePic.url field's name to FurniturePic.image. But, feel free to ignore it.