3

I am using django-reversion in my project. And it works good except one thing: I can't get previous versions of ManyToMany fields. But in django admin it is works, not in my code. To get previous version I use following code:

vprod = Version.objects.get_for_date(product, ondate).get_object_version().object

and it works except m2m field where 'product' is object of Product class,

class Product(models.Model):
    name = models.CharField(max_length=255)
    elements = models.ManyToManyField(Sku)

class Sku(models.Model):
    name = models.CharField(max_length=255, verbose_name="SKU Name")

I can get vprod.name and it returns what I need, but when I try vprod.elements.all() it returns list only the current (last) version, even if the number of elements changed.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
Eugene Nagorny
  • 1,626
  • 3
  • 18
  • 32
  • I want to receive just list of elements in defined time for my product. But code above returns only a list of elements only in last state, but name in defined time. – Eugene Nagorny Jul 01 '11 at 11:12

2 Answers2

4

I had the same issue and thanks to @Webthusiast's answer I got my working code. Adapting to your example would be something like this.

Imports:

from django.contrib.contenttypes.models import ContentType
import reversion

Register your models:

reversion.register(Sku)
reversion.register(Product, follow=['elements'])

And then you can iterate:

object = Product.objects.get(some_id)
versions = reversion.get_for_object(self.object)
for version in versions:
    elements = [v.object_version.object \
        for v in version.revision.version_set.all() \
        if v.content_type == ContentType.objects.get_for_model(Product)]

The documentation for this is now on Read the Docs. Refer to the 'Advanced model registration' section of the Low-level API page.

vmassuchetto
  • 1,529
  • 1
  • 20
  • 44
4

If I understand it correctly, I think you should get the revision for the version; the version contains the data of the object, the revision contains versions for multiple objects. Have a look at:

some_version.revision.version_set.all()

Concretely, I think you should use (untested):

[ v for v in Version.objects.get_for_date(product, ondate).revision.version_set.all() if version.content_type == ContentType.objects.get_for_model(Sku) ]

Note, btw, that reversions should know that it should follow relationships. Using the low level API:

reversion.register(YourModel, follow=["your_foreign_key_field"])

Webthusiast
  • 986
  • 10
  • 16
  • > reversion.register(YourModel, follow=["your_foreign_key_field"]) I did, some_version.revision.version_set.all() as I understand do almost the same as .get_object_version() – Eugene Nagorny Jul 01 '11 at 11:02
  • Have you tried it? `some_version.get_object_version()` gives a 'deserialized object', `some_version.revision.version_set.all` gives a queryset with the versions of all the (followed) objects at the same time as `some_version`. The problem with versions is that they refer to model instances, not to versions, so you should get the version of a followed model instance from the `some_version.revision.version_set`. – Webthusiast Jul 01 '11 at 11:42