Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

0.1.2
-----
* Bump up version
* Fix "Select all" issue

0.1.1
-----

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Django bulk admin enables you to bulk add, bulk edit, bulk upload and bulk selec

View the screenshots below to get an idea of how django bulk admin does look like.

Requires Django >= 1.7.
**This is a fork that is ahead of the master as my pull requests are not merged.** Supports Django 3 and 4. Seems to be working with Django 5.


===========
Expand Down
61 changes: 30 additions & 31 deletions bulk_admin/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@
from django.contrib import admin, messages
from django.contrib.admin.exceptions import DisallowedModelAdminToField
from django.contrib.admin.options import IS_POPUP_VAR, InlineModelAdmin, TO_FIELD_VAR, csrf_protect_m
from django.contrib.admin.templatetags.admin_static import static
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.contrib.admin.utils import NestedObjects, flatten_fieldsets
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.urlresolvers import reverse
from django.db import router, transaction
from django.forms.formsets import DELETION_FIELD_NAME, INITIAL_FORM_COUNT, TOTAL_FORM_COUNT, ManagementForm
from django.forms.models import modelform_defines_fields, modelformset_factory, BaseModelFormSet
from django.forms.utils import ErrorList
from django.http import HttpResponseRedirect
from django.template.response import SimpleTemplateResponse
from django.utils import six
from django.utils.encoding import force_text
from django.urls import reverse
from django.utils.encoding import force_str
from django.utils.text import get_text_list
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils.translation import gettext as _, gettext_lazy
from django.conf.urls.static import static
from functools import partial, update_wrapper

import django
Expand Down Expand Up @@ -65,7 +64,7 @@ def __init__(self, *args, **kwargs):
]

def get_urls(self):
from django.conf.urls import url
from django.urls import re_path

def wrap(view):
def wrapper(*args, **kwargs):
Expand All @@ -75,7 +74,7 @@ def wrapper(*args, **kwargs):
info = self.model._meta.app_label, self.model._meta.model_name

urlpatterns = super(BulkModelAdmin, self).get_urls()
urlpatterns.insert(0, url(r'^bulk/$', wrap(self.bulk_view), name='%s_%s_bulk' % info))
urlpatterns.insert(0, re_path(r'^bulk/$', wrap(self.bulk_view), name='%s_%s_bulk' % info))

return urlpatterns

Expand Down Expand Up @@ -158,7 +157,7 @@ def bulk_view(self, request, form_url='', extra_context=None):

formset = formset_class(**formset_params)

msg = _('The %s were bulk added successfully. You may edit them again below.') % (force_text(opts.verbose_name_plural),)
msg = _('The %s were bulk added successfully. You may edit them again below.') % (force_str(opts.verbose_name_plural),)
self.message_user(request, msg, messages.SUCCESS)

else:
Expand All @@ -175,23 +174,23 @@ def bulk_view(self, request, form_url='', extra_context=None):
if formset.is_bound:
errors.extend(formset.non_form_errors())
for formset_errors in formset.errors:
errors.extend(list(six.itervalues(formset_errors)))

context = dict(
self.admin_site.each_context(request) if django.VERSION >= (1, 8) else self.admin_site.each_context(),
bulk=True,
bulk_formset_prefix=prefix,
bulk_upload_fields=self.get_bulk_upload_fields(request),
title=_('Bulk add %s') % force_text(opts.verbose_name_plural),
is_popup=(IS_POPUP_VAR in request.POST or
errors.extend(list(iter(formset_errors.values())))

context = self.admin_site.each_context(request)
context.update({
'bulk': True,
'bulk_formset_prefix': prefix,
'bulk_upload_fields': self.get_bulk_upload_fields(request),
'title': _('Bulk add %s') % force_str(opts.verbose_name_plural),
'is_popup': (IS_POPUP_VAR in request.POST or
IS_POPUP_VAR in request.GET),
to_field=to_field,
media=media,
inline_admin_formsets=inline_formsets,
errors=errors,
preserved_filters=self.get_preserved_filters(request),
)

'to_field': to_field,
'media': media,
'inline_admin_formsets': inline_formsets,
'errors': errors,
'preserved_filters': self.get_preserved_filters(request),
'adminform': admin.helpers.AdminForm(ManagementForm(), [], {}),
})
context.update(extra_context or {})

return self.render_change_form(request, context, add=True, change=False, obj=None, form_url=form_url)
Expand All @@ -201,8 +200,8 @@ def response_bulk(self, request, formset):
opts = model._meta
preserved_filters = self.get_preserved_filters(request)
msg_dict = {
'name': force_text(opts.verbose_name),
'name_plural': force_text(opts.verbose_name_plural),
'name': force_str(opts.verbose_name),
'name_plural': force_str(opts.verbose_name_plural),
}

if IS_POPUP_VAR in request.POST:
Expand Down Expand Up @@ -273,7 +272,7 @@ def transform_post_and_files(self, request, prefix):
post.update({
'{}-{}-{}'.format(prefix, index, name): value
for name, value
in six.iteritems(form_data_for_file)
in iter(form_data_for_file.items())
})

return post, files, force_continue
Expand Down Expand Up @@ -312,25 +311,25 @@ def get_bulk_upload_fields(self, request):
@property
def media(self):
media = super(BulkModelAdmin, self).media
media.add_js([static('bulk_admin/js/bulk.js')])
media._js.extend([static('bulk_admin/js/bulk.js')])

return media

def select_related_action(self, request, queryset):
return self.response_bulk_popup(request, queryset)

select_related_action.short_description = ugettext_lazy('Select')
select_related_action.short_description = gettext_lazy('Select')

def bulk_edit_action(self, request, queryset):
model = self.model
opts = model._meta

selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
selected = queryset.values_list('pk', flat=True)
redirect_url = reverse('admin:%s_%s_bulk' % (opts.app_label, opts.model_name), current_app=self.admin_site.name)

return HttpResponseRedirect('{}?pks={}'.format(redirect_url, ','.join(selected)))

bulk_edit_action.short_description = ugettext_lazy('Bulk edit')
bulk_edit_action.short_description = gettext_lazy('Bulk edit')


class BulkInlineModelAdmin(InlineModelAdmin):
Expand Down
1 change: 1 addition & 0 deletions bulk_admin/static/bulk_admin/js/bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
}

$totalFormCountInput.attr('value', this.files.length);
$form.appendTo($('body'));
$form.submit();

submitted = true;
Expand Down
32 changes: 32 additions & 0 deletions example_project/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-07-24 20:07
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Image',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, unique=True)),
('data', models.FileField(blank=True, null=True, upload_to='')),
],
),
migrations.CreateModel(
name='Project',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, unique=True)),
('images', models.ManyToManyField(blank=True, to='example_project.Image')),
],
),
]
Empty file.
3 changes: 1 addition & 2 deletions example_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@
'example_project',
)

MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
Expand Down
2 changes: 1 addition & 1 deletion example_project/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.test import TestCase
from django.contrib.admin.sites import site as admin_site
from django.contrib.auth.models import Permission, User
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils import six
from io import BytesIO

Expand Down
4 changes: 2 additions & 2 deletions example_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
1. Add an import: from blog import urls as blog_urls
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
"""
from django.conf.urls import include, url
from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^admin/', admin.site.urls),
]
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Django==1.8.4
Django==2.0
tox==2.1.1
17 changes: 7 additions & 10 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@

setup(
name='django-bulk-admin',
version='0.1.1',
version='0.1.2',
packages=find_packages(exclude=('example_project*', 'screenshots',)),
include_package_data=True,
license='BSD',
description='Django bulk admin enables you to bulk add, bulk edit, bulk upload and bulk select in django admin.',
long_description=README,
url='https://github.com/purelabs/django-bulk-admin',
author='Ruben Grill',
url='https://github.com/jameslao/django-bulk-admin',
author='Ruben Grill, James Lao',
author_email='ruben.grill@gmail.com',
install_requires=[
'Django>=1.7',
'Django>=4.0',
],
classifiers=[
'Environment :: Web Environment',
Expand All @@ -28,12 +28,9 @@
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Software Development :: Libraries :: Python Modules',
],
)
13 changes: 6 additions & 7 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
[tox]
envlist =
py{27,32,33,34}-django{17,18}
py2-django1_11,
py3-django{1_11,2_0}

[testenv]
basepython =
py27: python2.7
py32: python3.2
py33: python3.3
py34: python3.4
py2: python2
py3: python3
commands = make test
deps =
django17: Django>=1.7,<1.8
django18: Django>=1.8,<1.9
django1_11: Django>=1.11,<1.12
django2_0: Django>=2.0,<2.1
whitelist_externals = make