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

Revision 713, 4.6 kB (checked in by jose.brandao, 2 years ago)

Fixing fossil index to work with key = value logic

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
83    def create_indexer(self, key, value):
84        """
85        Creates a fossil index for this fossil + given key and value
86        """
87        FossilIndexer.objects.get_or_create(
88                fossil=self,
89                key=key,
90                value=value,
91                )
92   
93class FossilIndexer(models.Model):
94    """
95    Class used to index fossil by field values. This is a sollution for querying
96    fossils withouth use search in the field 'serialized'. Of course, this is
97    because index + join is faster than like.
98    """
99    class Meta:
100        unique_together = (
101                ('fossil','key','value'),
102                )
103
104    fossil = models.ForeignKey('Fossil', related_name='indexeds')
105    key = models.CharField(max_length=250)
106    value = models.CharField(max_length=250)
107
108# SIGNALS
109from django.db.models import signals
110
111def fossil_post_save(sender, instance, signal, **kwargs):
112    # Updates old revisions setting them with "is_most_recent" as False
113    if instance.is_most_recent:
114        Fossil.objects.filter(
115                content_type=instance.content_type,
116                object_id=instance.object_id,
117                creation__lt=instance.creation,
118                is_most_recent=True,
119                ).exclude(
120                        pk=instance.pk,
121                        ).update(
122                                is_most_recent=False,
123                                )
124
125    # Gets "previous_revision" from last one
126    if not instance.previous_revision:
127        try:
128            instance.previous_revision = Fossil.objects.filter(
129                content_type=instance.content_type,
130                object_id=instance.object_id,
131                creation__lt=instance.creation,
132                ).exclude(
133                    pk=instance.pk,
134                    ).latest('creation')
135            instance.save()
136        except Fossil.DoesNotExist:
137            pass
138
139signals.post_save.connect(fossil_post_save, sender=Fossil)
Note: See TracBrowser for help on using the browser.