ninapavlich / django-batch-uploader

Django batch uploading
MIT License
8 stars 4 forks source link

TypeError: 'NoneType' object is not iterable #8

Open onyekaa opened 6 years ago

onyekaa commented 6 years ago

Hi,

Just installed this, followed the instructions but I keep getting this error when trying to save a new batch. Not sure how to resolve it. I've traced the line but the issue seems to be going over my head. Any ideas?

 File "/src/apps/django_batch_uploader/admin.py", line 69, in add_view
    response = self.batch_upload_response(request)
  File "/src/apps/django_batch_uploader/admin.py", line 174, in batch_upload_response
    output_fields = flatten_fieldsets(self.fieldsets)
  File "/lib/python2.7/site-packages/django/contrib/admin/utils.py", line 112, in flatten_fieldsets
    for name, opts in fieldsets:
TypeError: 'NoneType' object is not iterable
ninapavlich commented 6 years ago

Hi! Can you paste your model code and admin configuration code for reference?

onyekaa commented 6 years ago

Sorry for taking so long to reply, was distracted by another project.

Okay, So for the model I have this:

class Image(models.Model):
    image = models.ImageField(upload_to='film_photos')
    title = models.ForeignKey(Title)
    caption = models.CharField(max_length=200, blank=True)
    credit = models.CharField(max_length=60, blank=True)
    type = models.CharField(choices=TYPES, max_length=20)
    uploaded_by = models.ForeignKey(User, editable=False, null=True)
    uploaded_date = models.DateTimeField(auto_now=True, editable=False)

    def get_absolute_url(self):
        return reverse('title:image', args=[str(self.title.id), str(self.id)])

    def __str__(self):
        return '{0} {1} image'.format(self.caption if self.caption else self.title, self.id)

    class Meta:
        verbose_name = 'Movie Image'
        verbose_name_plural = 'Movie Images'

and

my admin code:


class BaseImageAdmin(BaseBatchUploadAdmin):

    batch_url_name = "admin_image_batch_view"

admin.site.register(Image, BaseImageAdmin)   

It's worth mentioning that I'm using Django suit for my admin, so I had to change the JS to hook onto the Suit's jQuery and comment out items that I couldn't replace

  // initGrappelliHooks: function(){
        //     $("#grp-content-container .grp-collapse").grp_collapsible({
        //         on_init: function(elem, options) {
        //             // open collapse (and all collapse parents) in case of errors
        //             if (elem.find("ul.errorlist").length > 0) {
        //                 elem.removeClass("grp-closed")
        //                     .addClass("grp-open");
        //                 elem.parents(".grp-collapse")
        //                     .removeClass("grp-closed")
        //                     .addClass("grp-open");
        //             }
        //         }
        //     });
        // },

            // this.initGrappelliHooks();

...

})( Suit.$, window, document );
ninapavlich commented 6 years ago

Hi @onyekaa,

I think you'll need to define a few more things in your admin definition:

1) fieldsets: This is a list of the model fields that are returned to the batch uploader when an item is uploaded successfully. See here for reference: https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets

2) media_file_name This is the name of the media file in your model -- in this case 'image'

3) default_fields and detail_fields This allows you to either bulk apply a field or individually apply a field. For example, if you're uploading five images, then it would be safe to assume that the 'uploaded_by' and 'uploaded_date' should be the same for all five images. But 'title', 'caption', 'credit' and 'type' should maybe be different for each image.

With those three things, try an admin definition that looks more like this:

class BaseImageAdmin(BaseBatchUploadAdmin):
    fieldsets = (
        (None, {
            'fields': ( 'image', 'title', 'caption', 'credit', 'type', 'uploaded_by', 'uploaded_date')
        })
    )
    media_file_name = 'image'
    default_fields = ['uploaded_by', 'uploaded_date']
    detail_fields = ['title', 'caption', 'credit', 'type']
    batch_url_name = "admin_image_batch_view"

 admin.site.register(Image, BaseImageAdmin)   

Let me know if this works out, or if you run into any other issues!

onyekaa commented 6 years ago

Forgot to mention that I defined some of those fields in my views.py, based off the example in the docs:

from django_batch_uploader.views import AdminBatchUploadView

class ImageBatchView(AdminBatchUploadView):

    model = Image
    media_file_name = 'image'
    default_fields = ['title', 'caption', 'credit', 'type']
    detail_fields = ['credit', 'type', 'caption']

    default_values = {}

and added this to my urls.py

url( r'admin/media/images/batch/$', ImageBatchView.as_view(), name="admin_image_batch_view"),

So they're supposed to be in the admin? I think I see what's missing though, the fieldsets option. I'll try it.

ninapavlich commented 6 years ago

Doh! You're exactly right, @onyekaa -- media_file_name, default_fields and detail_fields are supposed to be in views.py. It has been a little while since I wrote the documentation, so I just cross-referenced this with a working example.

It looks like the error you're encountering was just because of the first issue -- adding fieldsets to your admin.py configuration:

class BaseImageAdmin(BaseBatchUploadAdmin):
    fieldsets = (
        (None, {
            'fields': ( 'image', 'title', 'caption', 'credit', 'type', 'uploaded_by', 'uploaded_date')
        })
    )
    batch_url_name = "admin_image_batch_view"

 admin.site.register(Image, BaseImageAdmin)  

Does adding fieldsets to your admin solve the issue?

onyekaa commented 6 years ago

It worked. 😃 Thanks!

I just checked the readme and it's actually there. Did I miss that? If I did, sorry for the bother.

ninapavlich commented 6 years ago

Great! Nope, I just added it now so it's not confusing in the future.

As for the issue with initGrappelliHooks, do you need me to wrap that in a try/catch?

onyekaa commented 6 years ago

Ah okay.

Re: the hooks, you could, for the sake of others, but I'm trying to actually make a modification that works with Suit's theme, because right now it doesn't look great visually. If I did that, would you recommend I keep it separate or find a way to add it as some sort of setting to this one?

ninapavlich commented 6 years ago

Sorry for the delay - I missed your response!

A setting would be ideal, but in looking at the repo I think it might take a bit of re-working, because the references to Grappelli are peppered all over the place:

I think ideally the templates and javascript would be style-agnostic, and then we could optionally include a stylesheet that helps match the uploader to the style of the rest of the CMS.

I think this would require a little bit of an overhaul to remove the Grappelli code, but if you want to send me what you end up with, I'll try to integrate it so that it's more settings-based.

onyekaa commented 6 years ago

Hm. The whole thing works without the Grappelli styling/JS, it's just not as pretty, so yeah, you might be right about it being better as style-agnostic. I'll look into this.