summaryrefslogtreecommitdiff
path: root/django-simple-history/simple_history
diff options
context:
space:
mode:
Diffstat (limited to 'django-simple-history/simple_history')
-rwxr-xr-xdjango-simple-history/simple_history/__init__.py22
-rw-r--r--django-simple-history/simple_history/admin.py139
-rwxr-xr-xdjango-simple-history/simple_history/manager.py75
-rw-r--r--django-simple-history/simple_history/models.py169
-rw-r--r--django-simple-history/simple_history/templates/simple_history/object_history.html38
-rw-r--r--django-simple-history/simple_history/templates/simple_history/object_history_form.html24
6 files changed, 0 insertions, 467 deletions
diff --git a/django-simple-history/simple_history/__init__.py b/django-simple-history/simple_history/__init__.py
deleted file mode 100755
index 6df0b60b6..000000000
--- a/django-simple-history/simple_history/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import models
-
-
-registered_models = {}
-
-
-def register(model, app=None, manager_name='history'):
- """
- Create historical model for `model` and attach history manager to `model`.
-
- Keyword arguments:
- app -- App to install historical model into (defaults to model.__module__)
- manager_name -- class attribute name to use for historical manager
-
- This method should be used as an alternative to attaching an
- `HistoricalManager` instance directly to `model`.
- """
- if not model in registered_models:
- records = models.HistoricalRecords()
- records.manager_name = manager_name
- records.module = ("%s.models" % app) or model.__module__
- records.finalize(model)
diff --git a/django-simple-history/simple_history/admin.py b/django-simple-history/simple_history/admin.py
deleted file mode 100644
index 7d83e1016..000000000
--- a/django-simple-history/simple_history/admin.py
+++ /dev/null
@@ -1,139 +0,0 @@
-from django import template
-from django.core.exceptions import PermissionDenied
-from django.conf.urls.defaults import patterns, url
-from django.contrib import admin
-from django.contrib.admin import helpers
-from django.contrib.contenttypes.models import ContentType
-from django.core.urlresolvers import reverse
-from django.shortcuts import get_object_or_404, render_to_response
-from django.contrib.admin.util import unquote
-from django.utils.text import capfirst
-from django.utils.html import mark_safe
-from django.utils.translation import ugettext as _
-from django.utils.encoding import force_unicode
-
-
-class SimpleHistoryAdmin(admin.ModelAdmin):
- object_history_template = "simple_history/object_history.html"
- object_history_form_template = "simple_history/object_history_form.html"
-
- def get_urls(self):
- """Returns the additional urls used by the Reversion admin."""
- urls = super(SimpleHistoryAdmin, self).get_urls()
- admin_site = self.admin_site
- opts = self.model._meta
- info = opts.app_label, opts.module_name,
- history_urls = patterns("",
- url("^([^/]+)/history/([^/]+)/$",
- admin_site.admin_view(self.history_form_view),
- name='%s_%s_simple_history' % info),)
- return history_urls + urls
-
- def history_view(self, request, object_id, extra_context=None):
- "The 'history' admin view for this model."
- model = self.model
- opts = model._meta
- app_label = opts.app_label
- pk_name = opts.pk.attname
- history = getattr(model, model._meta.simple_history_manager_attribute)
- action_list = history.filter(**{pk_name: object_id})
- # If no history was found, see whether this object even exists.
- obj = get_object_or_404(model, pk=unquote(object_id))
- context = {
- 'title': _('Change history: %s') % force_unicode(obj),
- 'action_list': action_list,
- 'module_name': capfirst(force_unicode(opts.verbose_name_plural)),
- 'object': obj,
- 'root_path': getattr(self.admin_site, 'root_path', None),
- 'app_label': app_label,
- 'opts': opts
- }
- context.update(extra_context or {})
- context_instance = template.RequestContext(request, current_app=self.admin_site.name)
- return render_to_response(self.object_history_template, context, context_instance=context_instance)
-
- def history_form_view(self, request, object_id, version_id):
- original_model = self.model
- original_opts = original_model._meta
- history = getattr(self.model, self.model._meta.simple_history_manager_attribute)
- model = history.model
- opts = model._meta
- pk_name = original_opts.pk.attname
- record = get_object_or_404(model, **{pk_name: object_id, 'history_id': version_id})
- obj = record.instance
- obj._state.adding = False
-
- if not self.has_change_permission(request, obj):
- raise PermissionDenied
-
- if request.method == 'POST' and '_saveas_new' in request.POST:
- return self.add_view(request, form_url='../add/')
-
- formsets = []
- ModelForm = self.get_form(request, obj)
- if request.method == 'POST':
- form = ModelForm(request.POST, request.FILES, instance=obj)
- if form.is_valid():
- form_validated = True
- new_object = self.save_form(request, form, change=True)
- else:
- form_validated = False
- new_object = obj
- prefixes = {}
-
- if form_validated:
- self.save_model(request, new_object, form, change=True)
- form.save_m2m()
-
- change_message = self.construct_change_message(request, form, formsets)
- self.log_change(request, new_object, change_message)
- return self.response_change(request, new_object)
-
- else:
- form = ModelForm(instance=obj)
-
- adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj),
- self.prepopulated_fields, self.get_readonly_fields(request, obj),
- model_admin=self)
- media = self.media + adminForm.media
-
- url_triplet = (self.admin_site.name, original_opts.app_label,
- original_opts.module_name)
- context = {
- 'title': _('Revert %s') % force_unicode(obj),
- 'adminform': adminForm,
- 'object_id': object_id,
- 'original': obj,
- 'is_popup': False,
- 'media': mark_safe(media),
- 'errors': helpers.AdminErrorList(form, formsets),
- 'app_label': opts.app_label,
- 'original_opts': original_opts,
- 'changelist_url': reverse('%s:%s_%s_changelist' % url_triplet),
- 'change_url': reverse('%s:%s_%s_change' % url_triplet, args=(obj.pk,)),
- 'history_url': reverse('%s:%s_%s_history' % url_triplet, args=(obj.pk,)),
- # Context variables copied from render_change_form
- 'add': False,
- 'change': True,
- 'has_add_permission': self.has_add_permission(request),
- 'has_change_permission': self.has_change_permission(request, obj),
- 'has_delete_permission': self.has_delete_permission(request, obj),
- 'has_file_field': True,
- 'has_absolute_url': False,
- 'ordered_objects': opts.get_ordered_objects(),
- 'form_url': '',
- 'opts': opts,
- 'content_type_id': ContentType.objects.get_for_model(self.model).id,
- 'save_as': self.save_as,
- 'save_on_top': self.save_on_top,
- 'root_path': getattr(self.admin_site, 'root_path', None),
- }
- context_instance = template.RequestContext(request, current_app=self.admin_site.name)
- return render_to_response(self.object_history_form_template, context, context_instance)
-
- def save_model(self, request, obj, form, change):
- """
- Add the admin user to a special model attribute for reference after save
- """
- obj._history_user = request.user
- super(SimpleHistoryAdmin, self).save_model(request, obj, form, change)
diff --git a/django-simple-history/simple_history/manager.py b/django-simple-history/simple_history/manager.py
deleted file mode 100755
index 923b310eb..000000000
--- a/django-simple-history/simple_history/manager.py
+++ /dev/null
@@ -1,75 +0,0 @@
-from django.db import models
-
-
-class HistoryDescriptor(object):
- def __init__(self, model):
- self.model = model
-
- def __get__(self, instance, owner):
- if instance is None:
- return HistoryManager(self.model)
- return HistoryManager(self.model, instance)
-
-
-class HistoryManager(models.Manager):
- def __init__(self, model, instance=None):
- super(HistoryManager, self).__init__()
- self.model = model
- self.instance = instance
-
- def get_query_set(self):
- if self.instance is None:
- return super(HistoryManager, self).get_query_set()
-
- if isinstance(self.instance._meta.pk, models.OneToOneField):
- filter = {self.instance._meta.pk.name + "_id": self.instance.pk}
- else:
- filter = {self.instance._meta.pk.name: self.instance.pk}
- return super(HistoryManager, self).get_query_set().filter(**filter)
-
- def most_recent(self):
- """
- Returns the most recent copy of the instance available in the history.
- """
- if not self.instance:
- raise TypeError("Can't use most_recent() without a %s instance." %
- self.instance._meta.object_name)
- tmp = []
- for field in self.instance._meta.fields:
- if isinstance(field, models.ForeignKey):
- tmp.append(field.name + "_id")
- else:
- tmp.append(field.name)
- fields = tuple(tmp)
- try:
- values = self.values_list(*fields)[0]
- except IndexError:
- raise self.instance.DoesNotExist("%s has no historical record." %
- self.instance._meta.object_name)
- return self.instance.__class__(*values)
-
- def as_of(self, date):
- """
- Returns an instance of the original model with all the attributes set
- according to what was present on the object on the date provided.
- """
- if not self.instance:
- raise TypeError("Can't use as_of() without a %s instance." %
- self.instance._meta.object_name)
- tmp = []
- for field in self.instance._meta.fields:
- if isinstance(field, models.ForeignKey):
- tmp.append(field.name + "_id")
- else:
- tmp.append(field.name)
- fields = tuple(tmp)
- qs = self.filter(history_date__lte=date)
- try:
- values = qs.values_list('history_type', *fields)[0]
- except IndexError:
- raise self.instance.DoesNotExist("%s had not yet been created." %
- self.instance._meta.object_name)
- if values[0] == '-':
- raise self.instance.DoesNotExist("%s had already been deleted." %
- self.instance._meta.object_name)
- return self.instance.__class__(*values[1:])
diff --git a/django-simple-history/simple_history/models.py b/django-simple-history/simple_history/models.py
deleted file mode 100644
index 06054ba34..000000000
--- a/django-simple-history/simple_history/models.py
+++ /dev/null
@@ -1,169 +0,0 @@
-import copy
-from django.db import models
-from django.contrib import admin
-from django.contrib.auth.models import User
-from django.utils import importlib
-from manager import HistoryDescriptor
-
-
-class HistoricalRecords(object):
- def contribute_to_class(self, cls, name):
- self.manager_name = name
- self.module = cls.__module__
- models.signals.class_prepared.connect(self.finalize, sender=cls)
-
- def save_without_historical_record(self, *args, **kwargs):
- """Caution! Make sure you know what you're doing before you use this method."""
- self.skip_history_when_saving = True
- ret = self.save(*args, **kwargs)
- del self.skip_history_when_saving
- return ret
- setattr(cls, 'save_without_historical_record', save_without_historical_record)
-
- def finalize(self, sender, **kwargs):
- history_model = self.create_history_model(sender)
- module = importlib.import_module(self.module)
- setattr(module, history_model.__name__, history_model)
-
- # The HistoricalRecords object will be discarded,
- # so the signal handlers can't use weak references.
- models.signals.post_save.connect(self.post_save, sender=sender,
- weak=False)
- models.signals.post_delete.connect(self.post_delete, sender=sender,
- weak=False)
-
- descriptor = HistoryDescriptor(history_model)
- setattr(sender, self.manager_name, descriptor)
- sender._meta.simple_history_manager_attribute = self.manager_name
-
- def create_history_model(self, model):
- """
- Creates a historical model to associate with the model provided.
- """
- attrs = {'__module__': self.module}
-
- fields = self.copy_fields(model)
- attrs.update(fields)
- attrs.update(self.get_extra_fields(model, fields))
- attrs.update(Meta=type('Meta', (), self.get_meta_options(model)))
- name = 'Historical%s' % model._meta.object_name
- return type(name, (models.Model,), attrs)
-
- def copy_fields(self, model):
- """
- Creates copies of the model's original fields, returning
- a dictionary mapping field name to copied field object.
- """
- fields = {}
-
- for field in model._meta.fields:
- field = copy.copy(field)
- fk = None
-
- if isinstance(field, models.AutoField):
- # The historical model gets its own AutoField, so any
- # existing one must be replaced with an IntegerField.
- field.__class__ = models.IntegerField
-
- if isinstance(field, models.ForeignKey):
- field.__class__ = models.IntegerField
- #ughhhh. open to suggestions here
- try:
- field.rel = None
- except:
- pass
- try:
- field.related = None
- except:
- pass
- try:
- field.related_query_name = None
- except:
- pass
- field.null = True
- field.blank = True
- fk = True
- else:
- fk = False
-
- # The historical instance should not change creation/modification timestamps.
- field.auto_now = False
- field.auto_now_add = False
-
- if field.primary_key or field.unique:
- # Unique fields can no longer be guaranteed unique,
- # but they should still be indexed for faster lookups.
- field.primary_key = False
- field._unique = False
- field.db_index = True
- field.serialize = True
- if fk:
- field.name = field.name + "_id"
- fields[field.name] = field
-
- return fields
-
- def get_extra_fields(self, model, fields):
- """
- Returns a dictionary of fields that will be added to the historical
- record model, in addition to the ones returned by copy_fields below.
- """
- @models.permalink
- def revert_url(self):
- opts = model._meta
- return ('%s:%s_%s_simple_history' %
- (admin.site.name, opts.app_label, opts.module_name),
- [getattr(self, opts.pk.attname), self.history_id])
- def get_instance(self):
- return model(**dict([(k, getattr(self, k)) for k in fields]))
-
- return {
- 'history_id': models.AutoField(primary_key=True),
- 'history_date': models.DateTimeField(auto_now_add=True),
- 'history_user': models.ForeignKey(User, null=True),
- 'history_type': models.CharField(max_length=1, choices=(
- ('+', 'Created'),
- ('~', 'Changed'),
- ('-', 'Deleted'),
- )),
- 'history_object': HistoricalObjectDescriptor(model),
- 'instance': property(get_instance),
- 'revert_url': revert_url,
- '__unicode__': lambda self: u'%s as of %s' % (self.history_object,
- self.history_date)
- }
-
- def get_meta_options(self, model):
- """
- Returns a dictionary of fields that will be added to
- the Meta inner class of the historical record model.
- """
- return {
- 'ordering': ('-history_date', '-history_id'),
- }
-
- def post_save(self, instance, created, **kwargs):
- if not created and hasattr(instance, 'skip_history_when_saving'):
- return
- if not kwargs.get('raw', False):
- self.create_historical_record(instance, created and '+' or '~')
-
- def post_delete(self, instance, **kwargs):
- self.create_historical_record(instance, '-')
-
- def create_historical_record(self, instance, type):
- history_user = getattr(instance, '_history_user', None)
- manager = getattr(instance, self.manager_name)
- attrs = {}
- for field in instance._meta.fields:
- attrs[field.attname] = getattr(instance, field.attname)
- manager.create(history_type=type, history_user=history_user, **attrs)
-
-
-class HistoricalObjectDescriptor(object):
- def __init__(self, model):
- self.model = model
-
- def __get__(self, instance, owner):
- values = (getattr(instance, f.attname) for f in self.model._meta.fields)
- return self.model(*values)
diff --git a/django-simple-history/simple_history/templates/simple_history/object_history.html b/django-simple-history/simple_history/templates/simple_history/object_history.html
deleted file mode 100644
index d14338232..000000000
--- a/django-simple-history/simple_history/templates/simple_history/object_history.html
+++ /dev/null
@@ -1,38 +0,0 @@
-{% extends "admin/object_history.html" %}
-{% load i18n %}
-
-
-{% block content %}
- <div id="content-main">
-
- <p>{% blocktrans %}Choose a date from the list below to revert to a previous version of this object.{% endblocktrans %}</p>
-
- <div class="module">
- {% if action_list %}
- <table id="change-history">
- <thead>
- <tr>
- <th scope="col">{% trans 'Object' %}</th>
- <th scope="col">{% trans 'Date/time' %}</th>
- <th scope="col">{% trans 'Comment' %}</th>
- <th scope="col">{% trans 'Changed by' %}</th>
- </tr>
- </thead>
- <tbody>
- {% for action in action_list %}
- <tr>
- <td><a href="{{ action.revert_url }}">{{ action.history_object }}</a></td>
- <td>{{ action.history_date }}</td>
- <td>{{ action.get_history_type_display }}</td>
- <td><a href="{% url admin:auth_user_change action.history_user_id %}">{{ action.history_user }}</a></td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- {% else %}
- <p>{% trans "This object doesn't have a change history." %}</p>
- {% endif %}
- </div>
- </div>
-{% endblock %}
-
diff --git a/django-simple-history/simple_history/templates/simple_history/object_history_form.html b/django-simple-history/simple_history/templates/simple_history/object_history_form.html
deleted file mode 100644
index fdc8f1a87..000000000
--- a/django-simple-history/simple_history/templates/simple_history/object_history_form.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{% extends "admin/change_form.html" %}
-{% load i18n %}
-
-{% block breadcrumbs %}
- <div class="breadcrumbs">
- <a href="{% url admin:index %}">{% trans "Home" %}</a> &rsaquo;
- <a href="{% url admin:app_list app_label %}">{{app_label|capfirst|escape}}</a> &rsaquo;
- <a href="{{changelist_url}}">{{opts.verbose_name_plural|capfirst}}</a> &rsaquo;
- <a href="{{change_url}}">{{original|truncatewords:"18"}}</a> &rsaquo;
- <a href="../">{% trans "History" %}</a> &rsaquo;
- {% blocktrans with original_opts.verbose_name as verbose_name %}Revert {{verbose_name}}{% endblocktrans %}
- </div>
-{% endblock %}
-
-{% comment %}Hack to remove "Save as New" and "Save and Continue" buttons {% endcomment %}
-{% block content %}
- {% with 1 as is_popup %}
- {{block.super}}
- {% endwith %}
-{% endblock %}
-
-{% block form_top %}
- <p>{% blocktrans %}Press the save button below to revert to this version of the object.{% endblocktrans %}</p>
-{% endblock %}