Skip to content

Commit

Permalink
Enable the user to add custom fields in the admin
Browse files Browse the repository at this point in the history
  • Loading branch information
jpic committed Dec 5, 2011
1 parent d420495 commit 24231ce
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 3 deletions.
26 changes: 26 additions & 0 deletions admin_hack/__init__.py
@@ -1,4 +1,28 @@
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext as _
from django.core import urlresolvers
from django import http

def enable_custom_values(model, field_name=None):
#File "/srv/art/art_env/src/admin-hack/admin_hack/__init__.py", line 10, in enable_custom_values
#models.ForeignKey(model, null=True, blank=True).contribute_to_class(
#AttributeError: 'module' object has no attribute 'ForeignKey'
from django.db import models

if field_name is None:
field_name = model._meta.module_name.lower()

models.ForeignKey(model, null=True, blank=True).contribute_to_class(
models.get_model('admin_hack', 'CustomValue'), field_name)

def admin_export(modeladmin, request, queryset):
url = urlresolvers.reverse('admin_hack_export')
url += '?app=%s&model=%s' % (queryset.model._meta.app_label,
queryset.model._meta.module_name)
for item in queryset:
url += '&pk=%s' % (item.pk)
return http.HttpResponseRedirect(url)
admin_export.short_description = _(u'Export selected items to CSV')


def patch_admin(site, admin_hack_prefix='/admin_hack/'): def patch_admin(site, admin_hack_prefix='/admin_hack/'):
for model, options in site._registry.items(): for model, options in site._registry.items():
Expand All @@ -9,3 +33,5 @@ def patch_admin(site, admin_hack_prefix='/admin_hack/'):
'all': [settings.STATIC_URL + '/admin_hack/style.css'] 'all': [settings.STATIC_URL + '/admin_hack/style.css']
}) })
options.__class__.media = media options.__class__.media = media

options.__class__.actions.append(admin_export)
4 changes: 4 additions & 0 deletions admin_hack/admin.py
Expand Up @@ -3,6 +3,10 @@
from models import * from models import *
from forms import * from forms import *


class CustomValueInline(admin.TabularInline):
model = CustomValue
template = 'admin_hack/customvalue_tabularinline.html'

class FieldInline(admin.TabularInline): class FieldInline(admin.TabularInline):
model = Field model = Field
extra = 0 extra = 0
Expand Down
51 changes: 50 additions & 1 deletion admin_hack/models.py
@@ -1,9 +1,53 @@
from django.core import urlresolvers
from django.contrib import admin from django.contrib import admin
from django.db import models from django.db import models
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.db.models import signals from django.db.models import signals

from autoslug import AutoSlugField
from annoying.fields import AutoOneToOneField from annoying.fields import AutoOneToOneField


KIND_CHOICES = (
('float', _('number')),
('char', _('short text')),
('text', _('text')),
('datetime', _('date and time')),
('date', _('date only')),
('time', _('time only')),
('image', _('image')),
('file', _('file')),
)

class CustomValue(models.Model):
name = models.CharField(max_length=100)
slug = AutoSlugField(populate_from='name')

kind = models.CharField(choices=KIND_CHOICES, max_length=10)

float_value = models.FloatField(null=True, blank=True)
char_value = models.CharField(max_length=255, null=True, blank=True)
text_value = models.TextField(null=True, blank=True)
datetime_value = models.DateTimeField(null=True, blank=True)
date_value = models.DateField(null=True, blank=True)
time_value = models.TimeField(null=True, blank=True)
image_value = models.ImageField(null=True, blank=True,
upload_to='custom_value_images')
file_value = models.FileField(null=True, blank=True,
upload_to='custom_value_files')

@property
def value(self):
for k, v in KIND_CHOICES:
val = getattr(self, k + '_value', None)
if val is not None:
return val

def __unicode__(self):
return self.value

class Meta:
ordering = ('name',)

class AdminHackUserProfile(models.Model): class AdminHackUserProfile(models.Model):
user = AutoOneToOneField('auth.user', primary_key=True) user = AutoOneToOneField('auth.user', primary_key=True)
forms = models.ManyToManyField('Form', null=True, blank=True) forms = models.ManyToManyField('Form', null=True, blank=True)
Expand Down Expand Up @@ -33,14 +77,19 @@ class Meta:
('name', 'contenttype'), ('name', 'contenttype'),
) )


def get_absolute_url(self):
return urlresolvers.reverse('admin:admin_hack_form_change',
args=(self.pk,))

def to_dict(self): def to_dict(self):
return { return {
'name': self.name, 'name': self.name,
'pk': self.pk, 'pk': self.pk,
'contenttype': { 'contenttype': {
'pk': self.contenttype.pk, 'pk': self.contenttype.pk,
}, },
'field_set': [f.to_dict() for f in self.field_set.all()] 'field_set': [f.to_dict() for f in self.field_set.all()],
'absolute_url': self.get_absolute_url(),
} }


class Field(models.Model): class Field(models.Model):
Expand Down
5 changes: 3 additions & 2 deletions admin_hack/templates/admin_hack/hack.js
Expand Up @@ -158,7 +158,7 @@
} }


var html = [ var html = [
'<select id="_preset_change" style="display:inline">', '<select id="_preset_change" style="display:inline; vertical-align: top;">',
]; ];
for (var i in this.forms) { for (var i in this.forms) {
html.push('<option value="' + this.forms[i].pk + '">'); html.push('<option value="' + this.forms[i].pk + '">');
Expand All @@ -173,7 +173,8 @@
var user_profile = new UserProfile({{ request.user.adminhackuserprofile.to_dict|as_json }}); var user_profile = new UserProfile({{ request.user.adminhackuserprofile.to_dict|as_json }});


var change_view = new ChangeView({{ forms_dict|as_json }}); var change_view = new ChangeView({{ forms_dict|as_json }});
change_view.installSelect($('#content-main'), user_profile); var main = $('#content-main')
change_view.installSelect(main, user_profile);
{% if last_form_pk %} {% if last_form_pk %}
change_view.select.val({{ last_form_pk }}); change_view.select.val({{ last_form_pk }});
change_view.select.trigger('change'); change_view.select.trigger('change');
Expand Down
5 changes: 5 additions & 0 deletions admin_hack/urls.py
Expand Up @@ -11,6 +11,11 @@
views.JsHackView.as_view(), views.JsHackView.as_view(),
name='admin_hack_js_hack' name='admin_hack_js_hack'
), ),
url(
r'^export/$',
views.ExportView.as_view(),
name='admin_hack_export',
),
url( url(
r'^userprofile/(?P<pk>[0-9]+)/update/$', r'^userprofile/(?P<pk>[0-9]+)/update/$',
csrf_exempt(views.AdminHackUserProfileUpdateView.as_view()), csrf_exempt(views.AdminHackUserProfileUpdateView.as_view()),
Expand Down
13 changes: 13 additions & 0 deletions admin_hack/views.py
Expand Up @@ -24,6 +24,19 @@ def form_valid(self, form):
def form_invalid(self, form): def form_invalid(self, form):
return http.HttpResponse(form.errors, status=500) return http.HttpResponse(form.errors, status=500)


class ExportView(generic.TemplateView):
template_name = 'admin_hack/export.html'

def get_context_data(self, **kwargs):
self.model = get_model(request.GET.get('app'), request.GET.get('model'))
self.queryset = self.model.objects.filter(
pk__in=self.request.GET.get('pk'))

return {
'model': self.model,
'queryset': self.queryset,
}

class JsHackView(generic.TemplateView): class JsHackView(generic.TemplateView):
template_name = 'admin_hack/hack.js' template_name = 'admin_hack/hack.js'


Expand Down
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -21,5 +21,6 @@
'django_mptt (==0.5)', 'django_mptt (==0.5)',
'django_admin_tools (==0.4.0)', 'django_admin_tools (==0.4.0)',
'django_annoying', 'django_annoying',
'django_autoslug',
] ]
) )

0 comments on commit 24231ce

Please sign in to comment.