Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'tuple' object has no attribute '_committed' error while updating image objects?

Here I am trying to update each product image of a particular product. But it is not working properly. Here only the image of first object is updating.

There is a template where we can update product and product images at once. ProductImage has a ManyToOne relation with Product Model so in the template there can be multiple images objects of a single product.

Updating product model works fine but while updating ProductImage Objects it is not working.

Instead of zipping is there any other way to update multiple image objects at once ?

EDIT: If I unzip the images list then updating doesn't works properly. For example if I change the image of one object then the another object images changes. BUT when I change all the image objects images then the update works fine. It doesn't work properly when I change only some of the objects.

When I Zip then images list then this is the error traceback.

Traceback (most recent call last):
  File "venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "venv\lib\site-packages\django\core\handlers\base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "\venv\lib\site-packages\django\views\generic\base.py", line 73, in view
    return self.dispatch(request, *args, **kwargs)
  File "\venv\lib\site-packages\django\views\generic\base.py", line 101, in dispatch
    return handler(request, *args, **kwargs)
  File "dashboard\product\views\views.py", line 293, in post
    p.save()
  File "venv\lib\site-packages\django\db\models\base.py", line 751, in save
    force_update=force_update, update_fields=update_fields)
  File "venv\lib\site-packages\django\db\models\base.py", line 789, in save_base
    force_update, using, update_fields,
  File "venv\lib\site-packages\django\db\models\base.py", line 867, in _save_table
    for f in non_pks]
  File "lib\site-packages\django\db\models\base.py", line 867, in <listcomp>
    for f in non_pks]
  File "\venv\lib\site-packages\django\db\models\fields\files.py", line 303, in pre_save
    if file and not file._committed:
AttributeError: 'tuple' object has no attribute '_committed'

models

class ProductImage(models.Model):
    image = models.ImageField(upload_to='imgs',blank=True, null=True)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)

template

 <form method="post" enctype="multipart/form-data">
       {% csrf_token %}
       {{product_form}}
    <th>Current Image</th>
    <th>Change</th>
    {% for image in p_images %}
    <tr><td>{{image.pk}}</td>
    <td><img src="{{image.image.url}}" width="50" height="50"></td>
    <td><input type="file" name="image"></td>
    </tr>
    {% endfor %}
   <input type="submit">

views

def post(self, request, *args, **kwargs):
    product = Product.objects.get(pk=kwargs['pk'])
    product_form = ProductForm(request.POST, instance=product)
    images = zip(request.FILES.getlist('image')) 
    p_images = ProductImage.objects.filter(product=product).order_by('pk')
    if product_form.is_valid():
        product_form.save()             
        
       # updating product images 
        for p, img in zip(p_images, images):  # error is here
           p.image = img
           p.save()

           # Tried this way too:

       for img in images:
           ProductImage.objects.filter(product=product).update(image=img)
like image 229
D_P Avatar asked Oct 13 '20 08:10

D_P


2 Answers

First, change input name to be able to identify which ProductImage was updated.

<!-- <td><input type="file" name="image"></td> -->
     <td><input type="file" name="image-{{image.pk}}"></td>

Next, iterate the input_name in request.FILES and get the ProductImage PK.
Then, lookup the ProductImage p, update the image field and save the model.

def post(self, request, *args, **kwargs):
    product = Product.objects.get(pk=kwargs['pk'])
    product_form = ProductForm(request.POST, instance=product)
    if product_form.is_valid():
        product_form.save()

        # Updating product images
        if request.FILES:
            p_images = ProductImage.objects.filter(product=product).order_by('pk')
            p_images_lookup = {p_image.pk: p_image for p_image in p_images}
            for input_name in request.FILES:
                p = p_images_lookup[int(input_name[len('image-'):])]
                p.image = request.FILES[input_name]
                p.save()
like image 53
aaron Avatar answered Oct 15 '22 09:10

aaron


Problem

You’re unnecessarily zipping request.FILES.getlist(“images”) leading to an array containing tuples, each containing an image object.

Solution

Change

images = zip(request.FILES.getlist('image'))

To

images = request.FILES.getlist('image')

Reference

Django request.FILES.getlist usage: https://docs.djangoproject.com/en/3.1/topics/http/file-uploads/#uploading-multiple-files

like image 25
pygeek Avatar answered Oct 15 '22 08:10

pygeek