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
31 changes: 31 additions & 0 deletions configstore/.idea/configstore.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions configstore/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions configstore/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions configstore/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

777 changes: 777 additions & 0 deletions configstore/.idea/workspace.xml

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions configstore/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from configs import register, get_config, ConfigurationInstance
from forms import ConfigurationForm
import listeners
#from .configs import register, get_config, ConfigurationInstance
#from .forms import ConfigurationForm
#import configstore.listeners
19 changes: 10 additions & 9 deletions configstore/admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from filecmp import cmp

from django.contrib import admin
from django.shortcuts import render_to_response
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django import template

from models import Configuration
from configs import CONFIGS
from .models import Configuration
from .configs import CONFIGS

class ConfigurationAdmin(admin.ModelAdmin):
list_display = ('name', 'key', 'site')
Expand All @@ -31,17 +32,17 @@ def add_view(self, request, form_url='', extra_context=None):
model = self.model
opts = model._meta
app_label = opts.app_label
ordered_objects = opts.get_ordered_objects()
#ordered_objects = opts.get_ordered_objects()
obj = None
configs = CONFIGS.items()
def sort_by_label(a, b):
return cmp(a[1].name, b[1].name)
configs.sort(sort_by_label)
#configs.sort(sort_by_label)
context = {
'title': _('Select %s') % force_unicode(opts.verbose_name),
'title': _('Select %s') % opts.verbose_name,
'configs': configs,
#'adminform': adminForm,
'is_popup': request.REQUEST.has_key('_popup'),
#'is_popup': request.REQUEST.has_key('_popup'),
'show_delete': False,
#'media': mark_safe(media),
#'inline_admin_formsets': inline_admin_formsets,
Expand All @@ -55,7 +56,7 @@ def sort_by_label(a, b):
'has_delete_permission': self.has_delete_permission(request, obj),
'has_file_field': False, # FIXME - this should check if form or formsets have a FileField,
'has_absolute_url': hasattr(self.model, 'get_absolute_url'),
'ordered_objects': ordered_objects,
#'ordered_objects': ordered_objects,
'form_url': mark_safe(form_url),
'opts': opts,
'content_type_id': ContentType.objects.get_for_model(self.model).id,
Expand All @@ -66,6 +67,6 @@ def sort_by_label(a, b):
return render_to_response(self.change_form_template or [
"admin/%s/%s/add_form.html" % (app_label, opts.object_name.lower()),
"admin/%s/add_form.html" % app_label,
], context, context_instance=template.RequestContext(request))
], context)

admin.site.register(Configuration, ConfigurationAdmin)
11 changes: 6 additions & 5 deletions configstore/configs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib.sites.models import Site

from models import Configuration
#from settings import SITE_ID
from .models import Configuration

import threading

Expand All @@ -24,8 +24,9 @@ def get_config(self):
"""
#CONSIDER should we plug in caching here?
try:
Site.objects.clear_cache()
configuration = Configuration.objects.get(key=self.key, site=Site.objects.get_current())
except Configuration.DoesNotExist:
except Configuration.DoesNotExist or Exception:
return {}
else:
return configuration.data
Expand Down Expand Up @@ -95,7 +96,7 @@ def get_config(key):
The lazy object will be unique to each thread so values may be changed on the fly
The object also gets purged upon the begining of each request
'''
if key not in CONFIG_CACHE:
CONFIG_CACHE[key] = LazyDictionary(CONFIGS[key].get_config)
#if key not in CONFIG_CACHE:
CONFIG_CACHE[key] = LazyDictionary(CONFIGS[key].get_config)
return CONFIG_CACHE[key]

54 changes: 54 additions & 0 deletions configstore/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.conf import settings
from django.core.files.base import File
from django.core.files.storage import default_storage
from django.db.models.fields.files import FieldFile as _FieldFile
from django.utils.encoding import smart_str
import datetime
import os

CONFIGSTORE_FILE_PATH = getattr(settings, 'CONFIGSTORE_FILE_PATH', u'configstore/')
CONFIGSTORE_FILE_STORAGE = getattr(settings, 'CONFIGSTORE_FILE_STORAGE', default_storage)

class FieldFile(_FieldFile):
"""A file-like object, returned for `FileField` and `ImageField`."""

def __init__(self, name):
File.__init__(self, None, name)
self.storage = CONFIGSTORE_FILE_STORAGE
self._committed = True

def _require_file(self):
if not self:
raise ValueError("This instance has no file associated with it.")

def get_directory_name(self):
return os.path.normpath(datetime.datetime.now().strftime(smart_str(CONFIGSTORE_FILE_PATH)))

def get_filename(self, filename):
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))

def save(self, name, content):
name = os.path.join(self.get_directory_name(), self.get_filename(name))
self.name = self.storage.save(name, content)
# Update the filesize cache:
self._size = content.size
self._committed = True
save.alters_data = True

def delete(self):
# Only close the file if it's already open, which we know
# by the presence of self._file:
if hasattr(self, '_file'):
self.close()
del self.file

self.storage.delete(self.name)
self.name = None

# Delete the filesize cache
if hasattr(self, '_size'):
del self._size
self._committed = False
delete.alters_data = True


16 changes: 14 additions & 2 deletions configstore/forms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django import forms
from django.utils import simplejson
from django.core.files.base import File
import json
from django.contrib.sites.models import Site
from django.core.serializers.json import DjangoJSONEncoder

from models import Configuration
from .fields import FieldFile
from .models import Configuration

class ConfigurationForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
Expand All @@ -17,6 +19,16 @@ def __init__(self, *args, **kwargs):
if hasattr(value, 'pk'):
initial[key] = value.pk
self.initial.update(initial)

def clean(self):
if self.is_multipart:
# Save data for any File- or ImageFields:
for fld, value in self.cleaned_data.items():
if isinstance(value, File):
f = FieldFile(value.name)
f.save(value.name, value)
self.cleaned_data[fld] = f
return self.cleaned_data

def save(self, commit=True):
instance = super(ConfigurationForm, self).save(False)
Expand Down
2 changes: 1 addition & 1 deletion configstore/listeners.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from configs import CONFIG_CACHE, CONFIGS
from .configs import CONFIG_CACHE, CONFIGS
from django.core.signals import request_started

def nuke_cache(**kwargs):
Expand Down
29 changes: 29 additions & 0 deletions configstore/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 2.1 on 2018-09-11 22:45

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('sites', '0002_alter_domain_unique'),
]

operations = [
migrations.CreateModel(
name='Configuration',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=50)),
('_data', models.TextField(db_column='data')),
('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
],
),
migrations.AlterUniqueTogether(
name='configuration',
unique_together={('key', 'site')},
),
]
Empty file.
9 changes: 5 additions & 4 deletions configstore/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from django.db import models
from django.contrib.sites.models import Site
from serializer import make_serializers
from .serializer import make_serializers

ENCODER, DECODER = make_serializers()

class Configuration(models.Model):
key = models.CharField(max_length=50)
site = models.ForeignKey(Site)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
_data = models.TextField(db_column='data')

def get_data(self):
Expand All @@ -21,14 +21,15 @@ def set_data(self, data):

@property
def name(self):
from configs import CONFIGS
from .configs import CONFIGS
try:
return CONFIGS[self.key].name
except KeyError:
return self.key

def __unicode__(self):
def __str__(self):
return '%s: %s' % (self.key, self.site)

class Meta:
unique_together = [('key', 'site')]
app_label = 'configstore'
22 changes: 18 additions & 4 deletions configstore/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.query import QuerySet
from django.db import models
from django.utils import simplejson
import json

from decimal import Decimal

from .fields import FieldFile

class Handler(object):
def encode(self, obj):
'''
Expand Down Expand Up @@ -41,7 +43,7 @@ def decode(self, dct):
ct = ContentType.objects.get(app_label=dct.pop('app'),
model=dct.pop('model'))
try:
kwargs = dict([(str(key), value) for key, value in dct.iteritems()])
kwargs = dict([(str(key), value) for key, value in dct.items()])
return ct.get_object_for_this_type(**kwargs)
except ObjectDoesNotExist:
if not self.nullify_notfound:
Expand All @@ -58,8 +60,20 @@ def encode(self, obj):

def decode(self, dct):
return Decimal(dct['value'])

class FileHandler(Handler):
key = 'File'
instancetype = FieldFile

def encode(self, obj):
# `obj` is expected to be some type of `FieldFile`:
return {'__type__': self.key,
'name': obj.name}

def decode(self, dct):
return FieldFile(dct['name'])

class JSONDecoder(simplejson.JSONDecoder):
class JSONDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
kwargs.setdefault('object_hook', self.decode_objects)
self.handlers = kwargs.pop('handlers')
Expand All @@ -85,7 +99,7 @@ def default(self, obj):
return super(JSONEncoder, self).default(obj)

def make_serializers():
handlers = [ModelHandler(), DecimalHandler()]
handlers = [ModelHandler(), DecimalHandler(), FileHandler()]
#CONSIDER it might be a good idea to allow registering more serializers
return JSONEncoder(handlers=handlers), JSONDecoder(handlers=handlers)

Loading