Giter Club home page Giter Club logo

django-reversion's Introduction

django-reversion

PyPI latest PyPI Version PyPI License Github actions Docs

django-reversion is an extension to the Django web framework that provides version control for model instances.

Requirements

  • Python 3.7 or later
  • Django 3.2 or later

Features

  • Roll back to any point in a model instance's history.
  • Recover deleted model instances.
  • Simple admin integration.

Documentation

Check out the latest django-reversion documentation at Getting Started

Issue tracking and source code can be found at the main project website.

You can keep up to date with the latest announcements by joining the django-reversion discussion group.

Upgrading

Please check the Changelog before upgrading your installation of django-reversion.

Contributing

Bug reports, bug fixes, and new features are always welcome. Please raise issues on the django-reversion project site, and submit pull requests for any new code.

  1. Fork the repository on GitHub.
  2. Make a branch off of master and commit your changes to it.
  3. Install requirements.
  1. Run the tests
  1. Create a Pull Request with your contribution

Contributors

The django-reversion project was developed by Dave Hall and contributed to by many other people.

django-reversion's People

Contributors

agdude avatar blueyed avatar bourivouh avatar browniebroke avatar carlosxl avatar chicheng avatar claudep avatar daaray avatar eliast avatar erwinjunge avatar etianen avatar etienned avatar fladi avatar gavinwahl avatar geyser avatar gugu avatar ivissani avatar jedie avatar jmurty avatar kevinmarsh avatar kklingenberg avatar leo-naeka avatar meshy avatar michael-k avatar pcraston avatar pquentin avatar ticosax avatar tony avatar uruz avatar zsiciarz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-reversion's Issues

Release current version on PyPI.

Given the fact reversion seems to have made quite a bit progress since the last release, I'd like to encourage you to do a release on PyPI.

Statistics for edit/delete/create, by user?

Hi,

I'm looking at creating a statistics page for a Django app, listing all the users, and how many edits/creates/deletes etc. each has done.

Is there any functionality within reversion that might make this task easier?

Looking through the code, I can't seem to find anything obvious at the moment.

I'm thinking I can go through reversion_revision table, and drag the user_id column out of that. However, I'll need to parse the comment string in order to figure out whether it's a create, edit or delete.

And I'd also need to also go through reversion_version, and de-serialise the serialized_data column there to figure out which model each revision is for.

Is there any scope of getting some of this functionality into the reversion models themselves, or even creating a template (or templatetags) within reversion that might help with a statistics page?

Cheers,
Victor

Save last revision

In my application I wanted to access a revision after it is saved for use the information from it for various things. To facilitate this I made the following changes to revision.py and thought I would submit them back for inclusion if you find it acceptable. If you don't think it belongs, no worries, it is easy for me to maintain it separately and merge whenever you release a new version.

The changes are in my github repo: http://github.com/balsdorf/django-reversion
This is my first time using github so I am not sure if there is something special I should do to suggest a merge.

Thanks again for this great library.

Add field to indicate if a Version represents a create, update or delete operation

It would be convenient to have a field to indicate if a Version represents a create, update or delete operation.

After a quick breeze through the code I'm thinking this would happen in reversion/revisions.py during the end method, between lines 299 & 310. You're already looking up the latest_revision, which if it's None means it's a create. I don't know how to detect deletions though, changes are easy since they're all that's left once deletions are sorted.

Thoughts?

Let me know and I'll happily take a shot at a patch in a fork.

See: https://groups.google.com/group/django-reversion/browse_thread/thread/735eb3df95d0a2aa

Schema versioning

If I understand correctly, django-reversion currently supports versioning of data, but it doesn't really handle versioning of the schema itself. This approach keeps the overall solution simpler, but doesn't allow for one kick-ass feature: to be able to "go back in time" and see a given instance exactly how it existed at that time, that is, using the schema that was in use at that time.

Thoughts?

Disclaimer: I'm very new to South, I haven't really tried it yet. I've been reading the docs. Please excuse any misconception on my part of how it works.

The string 'Initial version.' is not translated when using the createinitialrevisions command.

When using the createinitialrevisions command with locale.getdefaultlocale() = ('fr_CA', 'UTF8') and settings.LANGUAGE_CODE = 'fr', the string 'Initial version.' used for the comment is not translated. I think it should be translated in french.

I verified that the translation exists in the .po and .mo files. No problem there.

It's probably a Django bug. Django command doesn't look to read settings.LANGUAGE_CODE for the moment. Ref.:
http://code.djangoproject.com/ticket/13860

File versioning and admin inlines

What steps will reproduce the problem?

  1. Unpack the attached test project, execute syncdb and runserver
  2. Log in to its admin interface
  3. Create an instance of TestModel with one inline TestFileModel
  4. Delete inline TestFileModel
  5. Try to revert to the first revision

What is the expected output? What do you see instead?
You won't be able to revert: the form won't validate because of missing
file. When TestFileModel contain only ptr and file fields (i.e. no "name"
field) you will be able to revert but the TestFileModel won't be restored.

What version of the product are you using? On what operating system?
django-reversion 1.2, django 1.1, python 2.6, linux.

Please provide any additional information below.
This issue is a different manifestation of a problem outlined in issue 41.

Reversion urls assume admin site instance is set with name attribute to "admin"

Reversion admin view urls (as they are reversed and sent to templates in the context instance) assume that AdminSite.name is admin (for namespacing purposes).

I've created a patch against master that should handle this case by fetching the attribute at runtime from the AdminSite instance attached to the VersionAdmin (or subclass thereof): thomlinton@b4a19f2

In addition, I'll make a pull request for convenience.

setup.py won't play nice with buildout and mr.developer

When using django-reversion with buildout, mr.developer djangorecipe the wrong paths are added to bin/django.wsgi.

The issue is the package dir in setup.py

package_dir={"reversion": "src/reversion"},

Should be

package_dir={"": "src"},

geodjango support

I'm trying to get reversion to work with geodjango. The first problem I found is that create_initial_revisions does not work:

The problem seems to be that it uses the default manager:
createinitialrevisions.py:90
for obj in model_class._default_manager.iterator():

But in geodjango the manager is replaced for GeoManager:
class MyModel(models.Model):
the_geom = models.PolygonField(srid=23031, null=True, blank=True)
objects = models.GeoManager()

Thanks in advance!

Viewing old versions doens't work for Inline formsets

The code doesn't pass prepopulated_fields to the formset.

diff --git a/src/reversion/admin.py b/src/reversion/admin.py
index c82d93d..5014352 100644
--- a/src/reversion/admin.py
+++ b/src/reversion/admin.py
@@ -282,8 +282,9 @@ class VersionAdmin(admin.ModelAdmin):
for inline, formset in zip(self.inline_instances, formsets):
fieldsets = list(inline.get_fieldsets(request, obj))
readonly = list(inline.get_readonly_fields(request, obj))

  •        prepopulated_fields = dict(inline.get_prepopulated_fields(request, obj))
         inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
    
  •            fieldsets, readonly, model_admin=self)
    
  •            fieldsets, prepopulated_fields, readonly, model_admin=self)
         inline_admin_formsets.append(inline_admin_formset)
    

Error in Tests that an entire revision can be recovered with MySQL (ver. 1.3.2)

I just upgrade to 1.3.2 and when I run the test suite I have now an error with this test:
Tests that an entire revision can be recovered.

I'm running Django 1.2.3, python 2.6 on OS X 10.6.4 and MySQL 5.1.46 with MySQL-python 1.2.3c1. I only have this error when using MySQL. The error is not present with SQLite (I didn't test Postgres). I tried running the test with only the Django apps loaded (contenttype, auth, etc.) and reversion and by running 'manage.py test reversion' without any change (still get the error).

So here's the traceback:

ERROR: Tests that an entire revision can be recovered.

Traceback (most recent call last):
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/reversion/tests.py", line 330, in testCanRecoverRevision
Version.objects.get_deleted(TestModel)[0].revision.revert()
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/reversion/models.py", line 32, in revert
version.revert()
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/reversion/models.py", line 118, in revert
self.object_version.save()
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/core/serializers/base.py", line 165, in save
models.Model.save_base(self.object, using=using, raw=True)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/models/base.py", line 527, in save_base
result = manager._insert(values, return_id=update_pk, using=using)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/models/manager.py", line 195, in _insert
return insert_query(self.model, values, **kwargs)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/models/query.py", line 1479, in insert_query
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 783, in execute_sql
cursor = super(SQLInsertCompiler, self).execute_sql(None)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 727, in execute_sql
cursor.execute(sql, params)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/db/backends/mysql/base.py", line 86, in execute
return self.cursor.execute(query, args)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/MySQLdb/cursors.py", line 173, in execute
self.errorhandler(self, exc, value)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (test_mmac.reversion_testrelatedmodel, CONSTRAINT relation_id_refs_id_e9ef11a5 FOREIGN KEY (relation_id) REFERENCES reversion_testmodel (id))')

What if my models are not in models.py

I am new the django world and have organized my models into smaller .py files, encompassed in a models folder. When I try to create the initial reversions, the error I get is "DatabaseError: no such column: reversion_version.type" . I'm guessing this has to do with my model organization. Is there a workaround?

UnicodeEncodeError in createinitialrevisions command when model verbose name have non-ASCII characters

When I run createinitialrevisions, if a modelโ€™s verbose name have non-ASCII characters in it, the command exit with an UnicodeEncodeError.

I'm on OS X 10.6.4 with stock python. Here's the traceback:

Traceback (most recent call last):
File "manage.py", line 11, in
execute_manager(settings)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/core/management/init.py", line 438, in execute_manager
utility.execute()
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/core/management/init.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/core/management/base.py", line 191, in run_from_argv
self.execute(_args, *_options.dict)
File "/Users/etienne/.virtualenvs/mmac/lib/python2.6/site-packages/django/core/management/base.py", line 220, in execute
output = self.handle(_args, *_options)
File "/Users/etienne/.virtualenvs/mmac/src/django-reversion/src/reversion/management/commands/createinitialrevisions.py", line 69, in handle
self.create_initial_revisions (app, model_class)
File "/Users/etienne/.virtualenvs/mmac/src/django-reversion/src/reversion/management/commands/createinitialrevisions.py", line 96, in create_initial_revisions
self.stdout.write(u"Created %s initial revisions for model %s.\n" % (created_count, model_class._meta.verbose_name))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 40: ordinal not in range(128)

The problem is with stdout.write() not using the correct encoding. I don't know why in my setup in this context sdtout is not using the correct encoding (utf-8)? LANG is set to fr_CA.UTF-8. In the python shell sys.sdtout.encoding = 'utf-8', locale.getdefaultlocale() = ('fr_CA', 'UTF8') and locale.getpreferredencoding() = 'UTF-8'.

If I replace sdtout.write() by print there's no more problem. Any reasons why you use sdtout.write() instead of print? print deal with the encoding. For more info: http://wiki.python.org/moin/PrintFails.

Error on creating initial versions if __unicode__ points to foreign key

When I run syncdb for the first time with a model where the unicode uses a foreign key I get the error:

TypeError: coercing to Unicode: need string or buffer, Question found

class Question(MP_Node):
title = models.CharField(max_length=254)

 def __unicode__(self):
    return self.title

class Answer(TimeStampedModel):
 question = models.ForeignKey(Question)

 def __unicode__(self):
    return self.question

ERROR ON SYNCDB:

root@CT162:/home/django/risk# python manage.py syncdb
Traceback (most recent call last):
File "manage.py", line 11, in
execute_manager(settings)
File "/usr/lib/python2.5/site-packages/django/core/management/init.py", line 438, in execute_manager
utility.execute()
File "/usr/lib/python2.5/site-packages/django/core/management/init.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/lib/python2.5/site-packages/django/core/management/base.py", line 191, in run_from_argv
self.execute(_args, *_options.dict)
File "/usr/lib/python2.5/site-packages/django/core/management/base.py", line 218, in execute
output = self.handle(_args, _options)
File "/usr/lib/python2.5/site-packages/django/core/management/base.py", line 347, in handle
return self.handle_noargs(
_options)
File "/usr/lib/python2.5/site-packages/django/core/management/commands/syncdb.py", line 103, in handle_noargs
emit_post_sync_signal(created_models, verbosity, interactive, db)
File "/usr/lib/python2.5/site-packages/django/core/management/sql.py", line 185, in emit_post_sync_signal
interactive=interactive, db=db)
File "/usr/lib/python2.5/site-packages/django/dispatch/dispatcher.py", line 162, in send
response = receiver(signal=self, sender=sender, *_named)
File "/usr/lib/python2.5/site-packages/reversion/management/init.py", line 45, in create_initial_revisions
version_save(unversioned_obj)
File "/usr/lib/python2.5/site-packages/reversion/revisions.py", line 326, in _create_on_success
self.end()
File "/usr/lib/python2.5/site-packages/reversion/revisions.py", line 289, in end
object_repr=unicode(obj))
TypeError: coercing to Unicode: need string or buffer, Question found

TO FIX

class Answer(TimeStampedModel):
 question = models.ForeignKey(Question)

 def __unicode__(self):
    return "%d" % self.id

Importing models causes already registered error

Sample case:

in appA.models.py:

import reversion
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=20)
reversion.register(MyModel)

in AppB.models.py:
from django.db import models
from appA.models import MyModel

class MyOtherModel(models.Model):
name = models.CharField(max_length=20)
other = models.ForeignKey(MyModel)

Save, sync db

now in django shell:

from appA.models import *
from appB.models import *

RegistrationError: class 'appA.models.MyModel' has already been registered with Reversion.

revision with json serialized_data fails upon DateField

Hi!

my reversioned model contains a DateField called "date". Django-reversion used to, and still does, work fine with that model if the serialized_data is xml. With json serialized_data it fails: see exception added below, reproduced in manage.py shell.

I narrowed down the problem to wrong json data: django-reverison produces a revision whith json serialized_data which contains "date": "2011-05-05 00:00:00". So if i change that to "date": "2011-05-05" everything's back to normal.

/path/to/latest/reversion/models.pyc in get_object_version(self)
    187         if isinstance(data, unicode):
    188             data = data.encode("utf8")
--> 189         return list(serializers.deserialize(self.format, data))[0]
    190 
    191     object_version = property(get_object_version,

/usr/lib/pymodules/python2.7/django/core/serializers/json.pyc in Deserializer(stream_or_string, **options)
     33     else:
     34         stream = stream_or_string
---> 35     for obj in PythonDeserializer(simplejson.load(stream), **options):
     36         yield obj
     37 

/usr/lib/pymodules/python2.7/django/core/serializers/python.pyc in Deserializer(object_list, **options)
    126             # Handle all other fields
    127             else:
--> 128                 data[field.name] = field.to_python(field_value)
    129 
    130         yield base.DeserializedObject(Model(**data), m2m_data)

/usr/lib/pymodules/python2.7/django/db/models/fields/__init__.pyc in to_python(self, value)
    609 
    610         if not ansi_date_re.search(value):
--> 611             raise exceptions.ValidationError(self.error_messages['invalid'])
    612         # Now that we have the date string in YYYY-MM-DD format, check to make

    613         # sure it's a valid date.


ValidationError: [u'Enter a valid date in YYYY-MM-DD format.']

File versioning, admin and ModelForms

What steps will reproduce the problem?

  1. Unpack the attached test project, execute syncdb and runserver
  2. Log in to its admin interface
  3. Create an instance of TestModel without uploading an image
  4. Edit the instance: change its title and upload an image
  5. Revert to the first revision of the instance
  6. BUG: The instance should be in the same state as before editing. The title was
    reverted correctly. However, the image was not deleted as it should be.
  7. Upload another image and save the model
  8. Revert to a revision with a previous version of an image
  9. BUG: The image is not changed by revert operation.

South Breaks Tests in test.py

When I run tests in my project that uses south after adding reversion, the reversion tests fail

Error: Database test_db couldn't be flushed. Possible reasons:
  * The database isn't running or isn't configured correctly.
  * At least one of the expected database tables doesn't exist.
  * The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
The full error: relation "reversion_testmodel_id_seq" does not exist
LINE 1: SELECT setval('"reversion_testmodel_id_seq"', 1, false);

It's not really an option modify settings with:

SOUTH_MIGRATION_MODULES = {
    'reversion': 'ignore',
}

As my migrations depend on reversion being installed so I reference them in south's depends_on

Could you possibly add something like:

from django.conf import settings
if not getattr(settings,'SKIP_REVERSION_TESTS', False):
     # All the tests

to tests.py? Then we could set SKIP_REVERSION_TESTS=True in settings.py when using south.

Update change_list template to duplicate less code for Django 1.3

http://code.djangoproject.com/ticket/12694
and http://code.djangoproject.com/changeset/14795

You should need to override much less of the change_form template now.

Not sure how you should handle supporting 1.3 at the same time as
earlier versions though. Unfortunately the simplest solution might be
to add the new Django 1.3 block into your template and continue
overriding the whole object-tools block.

Django really should implement extending object tools via a similar
mechanism to the way Admin actions are added.

Unit test error

I used django-reversion-1.4 in django-1.2.3.

When I ran ./manage.py test reversion, I got an error in every test method as below.

ERROR: Ensures the ignoring duplicates works across a foreign key.

Traceback (most recent call last):
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/django_reversion-1.4-py2.6.egg/reversion/tests.py", line 288, in setUp
TestModel.objects.all().delete()
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/query.py", line 440, in delete
for i, obj in izip(xrange(CHUNK_SIZE), del_itr):
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/query.py", line 106, in _result_iter
self._fill_cache()
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/query.py", line 760, in _fill_cache
self._result_cache.append(self._iter.next())
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/query.py", line 269, in iterator
for row in compiler.results_iter():
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/sql/compiler.py", line 672, in results_iter
for rows in self.execute_sql(MULTI):
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/models/sql/compiler.py", line 727, in execute_sql
cursor.execute(sql, params)
File "/home/leo/Synergy/construction/.ve/lib/python2.6/site-packages/Django-1.2.3-py2.6.egg/django/db/backends/postgresql_psycopg2/base.py", line 44, in execute
return self.cursor.execute(query, args)
DatabaseError: relation "reversion_testmodel" does not exist
LINE 1: ...estmodel"."id", "reversion_testmodel"."name" FROM "reversion...

It seems like that "reversion_testmodel" is not created when running unit test.
Is there any solution?

Thanks

Error on initial syncdb

I've tried registering just a single model, and also using the admin integration, but both methods give an error on the initial syncdb command. My model has about 2200 records.

Traceback (most recent call last):
File "manage.py", line 11, in
execute_manager(settings)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/init.py", line 438, in execute_manager
utility.execute()
File "/usr/local/lib/python2.6/dist-packages/django/core/management/init.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 191, in run_from_argv
self.execute(_args, *_options.dict)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 218, in execute
output = self.handle(_args, _options)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 347, in handle
return self.handle_noargs(
_options)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/commands/syncdb.py", line 103, in handle_noargs
emit_post_sync_signal(created_models, verbosity, interactive, db)
File "/usr/local/lib/python2.6/dist-packages/django/core/management/sql.py", line 185, in emit_post_sync_signal
interactive=interactive, db=db)
File "/usr/local/lib/python2.6/dist-packages/django/dispatch/dispatcher.py", line 162, in send
response = receiver(signal=self, sender=sender, *_named)
File "/usr/local/lib/python2.6/dist-packages/django_reversion-1.3.1-py2.6.egg/reversion/management/init.py", line 44, in create_initial_revisions
for unversioned_obj in model_class._default_manager.filter(pk__in=unversioned_ids).iterator():
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 269, in iterator
for row in compiler.results_iter():
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/compiler.py", line 672, in results_iter
for rows in self.execute_sql(MULTI):
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/compiler.py", line 727, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/util.py", line 15, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/sqlite3/base.py", line 200, in execute
return Database.Cursor.execute(self, query, params)

Inline model contents in Change History but lost on Save

Inline model contents are lost when a parent model instance is recovered following a deletion.

Perhaps I have not set django-reversion up properly but the low-level API documentation seems to say that making the parent model a subclass of VersionAdmin should be sufficient.

Plus the inline content is appearing correctly in the version preview. It is just not being saved.

I've tried registering both models via VersionAdmin as well as the API but have been unable to get the inline data to be restored. Please advise.

Steps to recreate:

  1. Vanilla install of Django (version 1.2.3) & Django-Reversion (version 1.3.2) - Python version 2.6.5.
  2. Setup Django app with model and admin definitions below. Document model has DocumentPage inline.
  3. Create a Document with a DocumentPage.
  4. Delete the Document.
  5. Choose "Recover deleted documents" option & select the version just deleted.
  6. Note that the Recover preview shows the inline DocumentPage correctly.
  7. Press Save.
  8. The parent Document is saved but the inline DocumentPage is not.

models.py:

class Document(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField()

class DocumentPage(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    document = models.ForeignKey(Document)

admin.py:

from django.contrib import admin
from reversion.admin import VersionAdmin
from demo.rev.models import Document, DocumentPage

class DocumentPageInline(admin.TabularInline):
    model = DocumentPage

class DocumentAdmin(VersionAdmin):
    inlines = [DocumentPageInline,]

class DocumentPageAdmin(VersionAdmin):
    pass

admin.site.register(Document, DocumentAdmin)
admin.site.register(DocumentPage, DocumentPageAdmin)

In case of auto-resolving parent class magic in proxies

We using deep magic for resolving proxy model when trying go get parent.

self.__class__ = PROXIES[self.type]

So if you trying to get Foo.objects.get() you get proxy model Bar. Reversion work not good is this cases so we add in method _follow_relationships something like this:

                parent_cls = obj._meta.parents.keys()[0]
                if self.is_registered(parent_cls):
                    parent_obj = parent_cls.objects.get(pk=obj.pk)
+                    parent_obj.__class__ = parent_cls
                    _follow_relationships(parent_obj)

may be this help you too...

Major new release of django-reversion

I'm hoping to do a major new release of django-reversion sometime in the next month. This release will aim to fix a number of long-running issues and add a number of long-requested features. It will be a backwards-incompatible release, and require a database migration to upgrade old installations.

Improvements to the public API will include:

  • A new addition/creation/deletion flag being added to the Version object.
  • A new, read-only admin interface for previewing and reverting/recovering revisions.
  • An improved interface for browsing old revisions by date.
  • New admin commands to migrate the database schema of old revisions.
  • A new admin command to selectively delete old revision data (suitable for a cronjob).

In addition, there are a number of possible changes to the API on which I'd like some community feedback:

Does reversion need to support different serialization backends?

At the moment, django-reversion stores a serialization format flag on each Version object. By standardizing on JSON, we could save a fair amount of storage space.

Does reversion need to support non-integer primary keys?

At the moment, reversion stores primary keys in a text field. By removing support for non-integer primary keys, it could switch to an integer field. This would allow for stricter database constraints to be enforced, and allow substantial optimizations to be added to tasks such as recovering deleted objects.

Does reversion need to provide diff-match-patch helpers?

Currently, reversion provides some helpers for integrating with the diff-match-patch library. Given that this integration is very short and easy, but adds a potential dependency to the codebase, I'd argue that it's best moved to a wiki page and dropped from the core codebase.

Does reversion need to support such an advanced low-level api?

At the moment, django-reversion exports a fairly advanced low-level api, allowing you to register models with reversion and then implicitly save new revisions via the django signalling framework. While this works quite well, it adds a lot of complexity to the system and necessitates maintaining a large stack of global mutable, thread-safe state.

It would be possible to transform the low level api into something more explicit. The new method of saving a revision would be something like this:

# views.py
obj1 = MyModel.objects.get(id=1)
obj1.name = "foo"
obj1.save()
obj2 = MyModel.objects.get(id=2)
obj2.name = "bar"
obj2.save()
Revision.objects.commit(obj1, obj2)

This is in contrast to the current method, which is something like this.

# models.py
reversion.register(MyModel)

# views.py
with reversion.revision():
    obj1 = MyModel.objects.get(id=1)
    obj1.name = "foo"
    obj1.save()
    obj2 = MyModel.objects.get(id=2)
    obj2.name = "bar"
    obj2.save()

I'd argue that both methods are conceptually easy to understand, but the first one is more explicit as to which objects are actually being saved in the revision. The first method also avoids a lot of dubious implementation details, such as thread local variables, and would make the reversion codebase substantially smaller.

Problems with the serialization of custom Fields

Using a custom field whose get_attname method returns something different than field.name leads to the field getting dropped in the serialization process.

the serializer tests for the field.attname in the list of fields

# django.core.serilizers.Serializer.serialize

if self.selected_fields is None or field.attname in self.selected_fields:
    self.handle_field(obj, field)

The RevisionManager takes the field.names to create the list of fields.

if fields is None:
    fields = [field.name for field in local_fields]

In order to not messup with realtion fields I would suggest something like this.

if fields is None:
  fields = [field.rel and field.name or field.attname for field in local_fields]

Here is an example where a field.attname is not equal with the field.name

http://djangosnippets.org/snippets/2294/

Allow follow to be a callable

Would be great in many circumstances where the ORM won't work or it would be less queries by doing some custom querying.

Error trying to recover deleted user

Not sure what I have done wrong? Reversion works for all the other models in my project, except for the auth_user. Traceback below:

Environment:

Request Method: GET
Request URL: http://127.0.0.1:8000/admin/auth/user/recover/52508/
Django Version: 1.2.3
Python Version: 2.6.5
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.admin',
 'django.contrib.humanize',
 'sorl.thumbnail',
 'ajax_select',
 'reversion']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.middleware.transaction.TransactionMiddleware',
 'reversion.middleware.RevisionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.middleware.csrf.CsrfResponseMiddleware',
 'edit.middleware.threadlocals.ThreadLocals',
 'edit.debug_middleware.DebugFooter',
 'edit.middleware.http.Http403Middleware')


Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
  100.                     response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/utils/decorators.py" in _wrapped_view
  76.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
  69.         response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/sites.py" in inner
  190.             return view(request, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/transaction.py" in _commit_on_success
  299.                     res = func(*args, **kw)
File "/usr/local/lib/python2.6/dist-packages/reversion/revisions.py" in _create_on_success
  319.                     result = func(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/reversion/admin.py" in recover_view
  275.         return self.render_revision_form(request, obj, version, context, recover=True)
File "/usr/local/lib/python2.6/dist-packages/reversion/admin.py" in render_revision_form
  211.                     del initial_row["id"]

Exception Type: KeyError at /admin/auth/user/recover/52508/
Exception Value: 'id'

Upgrade error report for createinitialrevisions

When trying to run the createinitialrevisions, and there are data errors, it would be very helpful to identify which model they result from, and the id of the specific model object

The current error trace looks like:

Traceback (most recent call last):
  File "manage.py", line 11, in <module>
    execute_manager(settings)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.6/dist-packages/reversion/management/commands/createinitialrevisions.py", line 69, in handle
    self.create_initial_revisions (app, model_class)
  File "/usr/local/lib/python2.6/dist-packages/reversion/management/commands/createinitialrevisions.py", line 92, in create_initial_revisions
    self.version_save(obj)
  File "/usr/local/lib/python2.6/dist-packages/reversion/revisions.py", line 319, in _create_on_success
    self.end()
  File "/usr/local/lib/python2.6/dist-packages/reversion/revisions.py", line 276, in end
    serialized_data = serializers.serialize(registration_info.format, [obj], fields=registration_info.fields)
  File "/usr/local/lib/python2.6/dist-packages/django/core/serializers/__init__.py", line 87, in serialize
    s.serialize(queryset, **options)
  File "/usr/local/lib/python2.6/dist-packages/django/core/serializers/base.py", line 48, in serialize
    self.handle_fk_field(obj, field)
  File "/usr/local/lib/python2.6/dist-packages/django/core/serializers/python.py", line 48, in handle_fk_field
    related = getattr(obj, field.name)
  File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/related.py", line 302, in __get__
    rel_obj = QuerySet(self.field.rel.to).using(db).get(**params)
  File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 341, in get
    % self.model._meta.object_name)
abc.models.DoesNotExist: Organisation matching query does not exist.

But it would be ideal if it said something like:

abc.models.DoesNotExist: Organisation matching query for Location 317 does not exist.

setup.py does not include management command

I'm using the trunk version, and when I run setup.py the commands folder in reversion.management is not included in the setup.

It works when I add "reversion.management.commands" to the packages variable in setup.py

AdminAction or queryset.update not recognized as change

Hi,

I created an Admin Action for my Models and they bypass reversion:

def make_published(self, request, queryset):
    rows_updated = queryset.update(status='p')
    if rows_updated == 1:
        message_bit = "1 story was"
    else:
        message_bit = "%s stories were" % rows_updated
    self.message_user(request, "%s successfully marked as published." % message_bit)

It's not working with the decorator nor with the "with"-statement. Where is the problem?

Circular Reference Support in Reversion

Setup:

  • Model A with M2M with Model C through Model B (which has FKs to Model A and C)
  • Model A also has a FK to Model B

Steps:

  1. Delete Model A (deleting the inlines of Model B) using django admin
  2. Revert Model A using reversion

Fails, as I'm guessing circular references are not supported...before I go chasing this down (since I'm still firefighting this problem in production right now!), can somebody please confirm that this is not supported yet and any advice/help on recovering...

I haven't lost data since the reversion has the model stored but is just unable to restore it without some help.

Thanks for that help :)

Recursive import with Django's comments and South breaks syncdb

What steps will reproduce the problem?

  1. add django.contrib.comments and a custom comment app (as defined in http://docs.djangoproject.com/en/dev/ref/contrib/comments/custom/) to your settings. The custom comment app needs to specify an own model, hence having a get_model function in its init.py.
  2. use South which hooks into the syncdb process
  3. use reversion

What is the expected output? What do you see instead?

Apparently there is a circular dependency between South and reversion when used with the comments app. South emits the post_syncdb signal which reversion is connected with, which then triggers the import of the admin modules of the synced app in reversion.management.create_initial_revisions. In case of the comments app this will trigger an import of the custom comment model and fails with a django.core.exceptions.ImproperlyConfigured because the custom comment app hasn't been loaded in the app cache yet.

What version of the product are you using? On what operating system?

Both, 1.3.1 and trunk.

DjangoUnicodeDecodeError where foreign key representation has a unicode character

DjangoUnicodeDecodeError at /skoolpal/mlibitemissue/add/

'ascii' codec can't decode byte 0xe0 in position 0: ordinal not in range(128)

Traceback:
File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/core/handlers/base.py" in get_response

  1.                 response = callback(request, _callback_args, *_callback_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/contrib/admin/options.py" in wrapper
  2.             return self.admin_site.admin_view(view)(_args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapped_view
  3.                 response = view_func(request, _args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  4.     response = view_func(request, _args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/contrib/admin/sites.py" in inner
  5.         return view(request, _args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/db/transaction.py" in _commit_on_success
  6.                 res = func(_args, *_kw)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/reversion/revisions.py" in _create_on_success
  7.                 result = func(_args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/reversion/admin.py" in add_view
  8.     return super(VersionAdmin, self).add_view(_args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapper
  9.         return decorator(bound_func)(_args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapped_view
  10.                 response = view_func(request, _args, *_kwargs)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/utils/decorators.py" in bound_func
  11.             return func(self, _args2, *_kwargs2)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/db/transaction.py" in _commit_on_success
  12.                 res = func(_args, *_kw)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/contrib/admin/options.py" in add_view
  13.             self.log_addition(request, new_object)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/reversion/admin.py" in log_addition
  14.     super(VersionAdmin, self).log_addition(request, object)
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/contrib/admin/options.py" in log_addition
  15.         object_repr     = force_unicode(object),
    
    File "/media/DATA/Dev/Python/.virtualenvs/trunk_skoolpal/lib/python2.6/site-packages/django/utils/encoding.py" in force_unicode
  16.         raise DjangoUnicodeDecodeError(s, *e.args)
    

Exception Type: DjangoUnicodeDecodeError at /skoolpal/mlibitemissue/add/
Exception Value: 'ascii' codec can't decode byte 0xe0 in position 0: ordinal not in range(128). You passed in <MLibItemIssue: [Bad Unicode data]> (<class 'common.models.library.issue.MLibItemIssue'>)

Add management command to clear revisions and versions for a specified app

When you're in development process, sometimes you need to remove an app that's no longer needed or you modified the app and the versions/revisons of this app are no longer valid, so you want to delete them.

I created a function (not a command for the moment) to do that. It was really just for a specific need, but if some people find it interesting I can upgrade it to a command and add all the proper check and exceptions. For the moment a reversion is not deleted if another app is involved in it.

Here's my rough function:
from django.contrib.contenttypes.models import ContentType

from reversion.models import Revision, Version

def delete_app_versions(app):
    content_types = ContentType.objects.filter(app_label__exact=app)
    all_revisions = set()
    for content_type in content_types:
        versions = Version.objects.filter(content_type__exact=content_type)
        for version in versions:
            all_revisions.add(version.revision_id)

    for revision_id in all_revisions:
        revision = Revision.objects.get(pk=revision_id)
        if not revision.version_set.exclude(content_type__in=content_types).count():
            Version.objects.filter(revision__exact=revision).delete()
            revision.delete()
        else:
            print 'Not deleting: %s' % revision

How to handle links to files?

I am not sure if this is the same as an issue already dealt with... but how do I handle the case where deleting an object which is linked to a file. When the object is first recovered by reversion, the file data and image show up in the editing form that is displayed, but as soon as the record is saved, the link to the file disappears (even though the file is still there) when the form is redisplayed.

FAIL: Tests that the revision is abandoned on error. on MySQL

I have a strange error. When I run the tests on my development environnement (OS X, MySQL) this test doesn't fail. But when I run the tests on my production server (Linux Ubuntu 10.04, MySQL) this test fail. The rollback doesn't seem to work?

FAIL: Tests that the revision is abandoned on error.

Traceback (most recent call last):
File "/home/mmac/virtualenvs/staging/src/django-reversion/src/reversion/tests.py", line 109, in testRevisionAbandonedOnError
self.assertEqual(Version.objects.get_for_object(test).count(), 1)
AssertionError: 2 != 1

Automatically adding created_on and updated_on to revisioned models

I have added this manually to my models but I feel like it should be added automatically when a model is registered to reversioning.

Here is the code I used:

def SomeModel(models.Model):
def get_versions_reversion_ids(self):
return [version.revision_id for version in Version.objects.get_for_object(self)]

    def created_on(self):
       return (Revision.objects.all().filter(id__in=self.get_versions_reversion_ids())[:1] or [None])[0].date_created

       def updated_on(self):
               updated = (Revision.objects.all().filter(id__in=self.get_versions_reversion_ids()).order_by('-date_created')[:1] or [None])[0].date_created

       return updated if updated != self.created_on() else None

Is there a better way to implement this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.