Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added initial skel and models.

  • Loading branch information...
commit 1a3b557db9b3a94187868f10bf9ec263d7c7a648 0 parents
@ionelmc authored
9 .gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+*.pyc
+*~
+.*.sw[po]
+dist/
+*.egg-info
+build/
+.build/
+pip-log.txt
1  AUTHORS
@@ -0,0 +1 @@
+Ionel Mărieș Cristian
9 LICENSE
@@ -0,0 +1,9 @@
+Copyright (c) 2011, Ionel Cristian Maries
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5 MANIFEST.in
@@ -0,0 +1,5 @@
+graft src/admin_customizer/static
+graft src/admin_customizer/templates
+include README.rst
+include LICENSE
+include README
1  README
73 README.rst
@@ -0,0 +1,73 @@
+===============================
+ django-admin-customizer
+===============================
+
+
+Django admin customizing interface
+
+Features
+========
+
+* Multiple admin instances for the same model
+* Customization of:
+
+ * list_display
+ * list_filter
+ * raw_id_fields
+ * actions
+ * search_fields
+
+Requirements
+============
+
+* Django (versions tbd)
+
+
+Installation guide
+==================
+
+Install from pypi, with pip::
+
+ pip install django-admin-customizer
+
+Or with setuptools::
+
+ easy_install django-admin-customizer
+
+Add ``admin_customizer`` to ``INSTALLED_APPS``::
+
+ INSTALLED_APPS += ("admin_customizer", )
+
+After that you need to run::
+
+ manage.py syncdb
+
+Or if you use south::
+
+ manage.py syncdb --migrate
+
+..note ::
+
+ You need to run syndb/migrate after each model change to have the admins and
+ customization interface working.
+
+``django-admin-customizer`` has static files for widgets in the edit interface.
+If you use staticfiles just run::
+
+ manage.py collectstatic
+
+If you do not use django.contrib.staticfiles you must manually symlink the
+site-packages/admin_customizer/static/admin_customizer dir to <your media root>/admin_customizer.
+
+Making extra actions available
+==============================
+
+Settings
+========
+
+Screenshots
+===========
+
+Edit page:
+
+.. image:: https://github.com/downloads/ionelmc/xxx
32 setup.py
@@ -0,0 +1,32 @@
+# -*- encoding: utf8 -*-
+from setuptools import setup, find_packages
+
+import os
+
+setup(
+ name = "django-admin-customizer",
+ version = "0.1",
+ url = 'https://github.com/ionelmc/django-admin-customizer',
+ download_url = '',
+ license = 'BSD',
+ description = "Django admin customizing interface",
+ long_description = file(os.path.join(os.path.dirname(__file__), 'README.rst')).read(),
+ author = 'Ionel Cristian Mărieș',
+ author_email = 'contact@ionelmc.ro',
+ packages = find_packages('src'),
+ package_dir = {'':'src'},
+ include_package_data = True,
+ install_requires = [
+ 'Django',
+ ],
+ zip_safe = False,
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Framework :: Django',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: WWW/HTTP',
+ ]
+)
0  src/admin_customizer/__init__.py
No changes.
37 src/admin_customizer/actions.py
@@ -0,0 +1,37 @@
+from django.utils.translation import ugettext_lazy as _
+
+available_actions = []
+
+def register(func):
+ if func not in available_actions:
+ available_actions.append(func)
+ return func
+
+@register
+def export_as_csv(modeladmin, request, queryset, header=True):
+ """
+ Generic csv export admin action.
+ based on http://djangosnippets.org/snippets/1697/
+ """
+ opts = modeladmin.model._meta
+ field_names = set([field.name for field in opts.fields])
+
+ response = HttpResponse(mimetype='text/csv')
+ response['Content-Disposition'] = 'attachment; filename=%s.csv' % unicode(opts).replace('.', '-')
+
+ writer = csv.writer(response)
+ if header:
+ writer.writerow(list(field_names))
+ def output(obj, field):
+ out = getattr(obj, "get_%s_display" % field, None)
+ if out:
+ out = out()
+ else:
+ out = getattr(obj, field, None)
+ return unicode(out).encode("utf-8","replace")
+
+ for obj in queryset:
+ writer.writerow([output(obj, field) for field in field_names])
+ return response
+
+export_as_csv.description = _("Export selected objects as CSV file")
0  src/admin_customizer/admin.py
No changes.
26 src/admin_customizer/managers.py
@@ -0,0 +1,26 @@
+from django.db import models
+
+def get_type_for(field):
+ if isinstance(field, models.ForeignKey):
+ return 'fk'
+ elif isinstance(field, models.ManyToManyField):
+ return 'mtm'
+ elif isinstance(field, models.OneToOneField):
+ return 'oto'
+ else:
+ return 'other'
+
+class AvailableFieldManager(models.Manager):
+ def get_by_field(self, model, field):
+ return self.get(
+ name = field.name,
+ type = get_type_for(field),
+ model = model
+ )
+
+ def create_by_field(self, model, field):
+ return self.create(
+ name = field.name,
+ type = get_type_for(field),
+ model = model
+ )
117 src/admin_customizer/models.py
@@ -0,0 +1,117 @@
+import sys
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.db.models.signals import class_prepared
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes.management import update_contenttypes
+from django.db.models import get_apps, get_models, signals
+from django.utils.encoding import smart_unicode
+from django.utils.importlib import import_module
+
+from .managers import AvailableFieldManager
+
+def update_available_fields(app, created_models, verbosity=2, **kwargs):
+ if isinstance(app, basestring):
+ app = import_module(app + '.models')
+ update_contenttypes(app, created_models, verbosity=verbosity, **kwargs)
+
+ available_fields = list(AvailableField.objects.filter(model__app_label=app.__name__.split('.')[-2]))
+ app_models = get_models(app)
+ if not app_models:
+ return
+ for klass in app_models:
+ opts = klass._meta
+ ct = ContentType.objects.get(app_label=opts.app_label,
+ model=opts.object_name.lower())
+ for field in opts.fields:
+ try:
+ af = AvailableField.objects.get_by_field(ct, field)
+ available_fields.remove(af)
+ except AvailableField.DoesNotExist:
+ af = AvailableField.objects.create_by_field(ct, field)
+ if verbosity >= 2:
+ print "Adding %s" % af
+ if available_fields:
+ if kwargs.get('interactive', False):
+ display = '\n'.join([' %s' % af for af in available_fields])
+ ok_to_delete = raw_input("""The following available fields do not exist anymore and need to be deleted:
+
+%s
+
+Any admins using this fields will be affected (they will be removed from them).
+
+ Type 'yes' to continue, or 'no' to cancel: """ % display)
+ else:
+ ok_to_delete = False
+
+ if ok_to_delete == 'yes':
+ for af in available_fields:
+ if verbosity >= 2:
+ print "Deleting stale %s" % af
+ ct.delete()
+ else:
+ if verbosity >= 2:
+ print "Stale available fields remain."
+
+signals.post_syncdb.connect(update_available_fields)
+
+try:
+ from south.signals import post_migrate
+except ImportError:
+ pass
+else:
+ def south_update_available_fields(app, **kwargs):
+ interactive = False
+ frame = sys._getframe(1)
+ while frame:
+ if frame.f_code.co_name == 'migrate_app':
+ if 'interactive' in frame.f_locals:
+ interactive = frame.f_locals['interactive']
+ break
+ frame = frame.f_back
+ update_available_fields(app, (), interactive=interactive, **kwargs)
+ post_migrate.connect(south_update_available_fields)
+
+class AdminSite(models.Model):
+ slug = models.SlugField()
+
+
+class RegisteredModel(models.Model):
+ model = models.ForeignKey("contenttypes.ContentType")
+ list_display = models.ManyToManyField(
+ "AvailableField",
+ related_name = "registeredmodels_with_list_display"
+ )
+ list_filter = models.ManyToManyField(
+ "AvailableField",
+ related_name = "registeredmodels_with_list_filter"
+ )
+ search_fields = models.ManyToManyField(
+ "AvailableField",
+ related_name = "registeredmodels_with_search_fields"
+ )
+ raw_id_fields = models.ManyToManyField("AvailableField",
+ related_name = "registeredmodels_with_",
+ limit_choices_to = {'type__in': ('oto', 'fk', 'mtm')}
+ )
+
+class AvailableField(models.Model):
+ model = models.ForeignKey("contenttypes.ContentType")
+ name = models.TextField()
+ TYPES = (
+ ('fk', _("Foreign key field")),
+ ('mtm', _("Many to many field")),
+ ('oto', _("One to one field")),
+ ('other', _("Other type of field"))
+ )
+ type = models.CharField(max_length=10, choices=TYPES)
+
+ objects = AvailableFieldManager()
+
+ def __str__(self):
+ return "AvailableField '%s | %s | %s'" % (
+ self.model,
+ self.name,
+ self.type
+ )
0  src/admin_customizer/views.py
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.