root/sandbox/django-fossil/fossil/models.py @ 712

Revision 712, 4.3 kB (checked in by jose.brandao, 2 years ago)

Support for fossil indexing

Line 
1import hashlib, datetime
2
3from django.db import models
4from django.core.serializers import serialize, deserialize
5from django.contrib.contenttypes.models import ContentType
6from django.contrib.contenttypes.generic import GenericForeignKey
7
8class FossilManager(models.Manager):
9    def create_for_object(self, obj):
10        if hasattr(obj, 'serialize_for_fossil'):
11            serialized = obj.serialize_for_fossil()
12        else:
13            serialized = serialize('json', [obj])
14
15        hash_key = hashlib.sha256(serialized).hexdigest()
16
17        return Fossil.objects.get_or_create(
18                pk=hash_key,
19                defaults={
20                    'serialized': serialized,
21                    'display_text': unicode(obj),
22                    'content_type': ContentType.objects.get_for_model(obj),
23                    'object_id': unicode(obj.pk),
24                    },
25                )[0]
26
27    def fossils_of_object(self, obj):
28        """
29        Returns a list of fossils of a given object, ordered by date
30        """
31        qs = self.get_query_set()
32        c_type = ContentType.objects.get_for_model(obj)
33
34        return qs.filter(content_type=c_type, object_id=obj.pk).order_by('creation')
35
36    def indexed(self, **kwargs):
37        """
38        Find fossils by fossil indexes
39        """
40        qs = self.get_query_set()
41
42        # Find all indexes by given key and value
43        indexeds = FossilIndexer.objects.all()
44        for k,v in kwargs.items():
45            indexeds = indexeds.filter(**{'key': k, 'value': v})
46
47        pks = indexeds.distinct().values_list('fossil', flat=True)
48
49        return qs.filter(pk__in=pks)
50
51class Fossil(models.Model):
52    objects = FossilManager()
53
54    id = models.CharField(max_length=64, primary_key=True)
55    serialized = models.TextField(blank=True, default='')
56    display_text = models.TextField(blank=True, default='')
57    creation = models.DateTimeField(blank=True, default=datetime.datetime.now)
58    content_type = models.ForeignKey(ContentType)
59    object_id = models.TextField()
60    object = GenericForeignKey()
61    is_most_recent = models.BooleanField(blank=True, default=True, db_index=True)
62    previous_revision = models.ForeignKey('self', null=True, blank=True)
63
64    def __unicode__(self):
65        return self.display_text
66
67    def get_object_fossil(self):
68        """
69        Returns the stored version of this object.
70        """
71
72        data = self.serialized
73
74        if isinstance(data, unicode):
75            data = data.encode("utf8")
76
77        manager = self.content_type.model_class().objects
78        if hasattr(manager, 'deserialize_for_fossil'):
79            return manager.deserialize_for_fossil(data)
80        else:
81            return list(deserialize('json', data))[0]
82   
83class FossilIndexer(models.Model):
84    """
85    Class used to index fossil by field values. This is a sollution for querying
86    fossils withouth use search in the field 'serialized'. Of course, this is
87    because index + join is faster than like.
88    """
89    class Meta:
90        unique_together = (
91                ('fossil','key','value'),
92                )
93
94    fossil = models.ForeignKey('Fossil', related_name='indexeds')
95    key = models.CharField(max_length=250)
96    value = models.CharField(max_length=250)
97
98# SIGNALS
99from django.db.models import signals
100
101def fossil_post_save(sender, instance, signal, **kwargs):
102    # Updates old revisions setting them with "is_most_recent" as False
103    if instance.is_most_recent:
104        Fossil.objects.filter(
105                content_type=instance.content_type,
106                object_id=instance.object_id,
107                creation__lt=instance.creation,
108                is_most_recent=True,
109                ).exclude(
110                        pk=instance.pk,
111                        ).update(
112                                is_most_recent=False,
113                                )
114
115    # Gets "previous_revision" from last one
116    if not instance.previous_revision:
117        try:
118            instance.previous_revision = Fossil.objects.filter(
119                content_type=instance.content_type,
120                object_id=instance.object_id,
121                creation__lt=instance.creation,
122                ).exclude(
123                    pk=instance.pk,
124                    ).latest('creation')
125            instance.save()
126        except Fossil.DoesNotExist:
127            pass
128
129signals.post_save.connect(fossil_post_save, sender=Fossil)
Note: See TracBrowser for help on using the browser.