Review Board

beta

Add a Base64Field and a FakeChangeFieldType evolution mutation

Updated 7 months, 3 weeks ago

Christian Hammond Reviewers
trunk reviewboard
None Navi
This change adds two things to Djblets that we need for the new parent diffs change for Review Board.

The first is a Base64Field, which works like a TextField but encodes/decodes Base64 behind the scenes.
We use it now for the diff fields in FileDiff, instead of accessing a TextField through getters/setters.

The second is a "mutation" class for use with Django Evolution. Django Evolution is the database migration
framework we're going to be using in Review Board. This class fakes a field type change, so that we can
perform the migration from TextField to Base64Field in order to satisfy Django Evolution's checks.
Made sure database migration worked with this change and the change in Review Board. Also made sure diffs
continued to work (viewing existing diffs, uploading and viewing new diffs) and all unit tests passed.

Diff revision 1 (Latest)

  1. /trunk/djblets/djblets/util/dbevolution.py: 1 change [ new content ]
  2. /trunk/djblets/djblets/util/fields.py: 2 changes [ 1 2 ]
/trunk/djblets/djblets/util/dbevolution.py
New File
1
from django_evolution.mutations import *
2
3
4
class FakeChangeFieldType(BaseMutation):
5
    """
6
    Changes the type of the field to a similar type.
7
    This is intended only when the new type is really a version of the
8
    old type, such as a subclass of that Field object. The two fields
9
    should be compatible or there could be migration issues.
10
    """
11
    def __init__(self, model_name, field_name, new_type):
12
        self.model_name = model_name
13
        self.field_name = field_name
14
        self.new_type = new_type
15
16
    def __str__(self):
17
        return "FakeChangeFieldType('%s', '%s', '%s')" % \
18
            (self.model_name, self.field_name, self.new_type)
19
20
    def simulate(self, app_label, proj_sig):
21
        app_sig = proj_sig[app_label]
22
        model_sig = app_sig[self.model_name]
23
        field_dict = model_sig['fields']
24
        field_sig = field_dict[self.field_name]
25
26
        field_sig['field_type'] = self.new_type
27
28
    def mutate(self, app_label, proj_sig):
29
        # We can just call simulate, since it does the same thing.
30
        # We're not actually generating SQL, but rather tricking
31
        # Django Evolution.
32
        self.simulate(app_label, proj_sig)
33
        return ""
/trunk/djblets/djblets/util/fields.py
Revision 11756 New Change
21
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
26
26
import base64
27
from datetime import datetime
27
from datetime import datetime
28
28
29
from django.db import models
29
from django.db import models
30
from django.dispatch import dispatcher
31
32
33
class Base64DecodedValue(str):
34
    """
35
    A subclass of string that can be identified by Base64Field, in order
36
    to prevent double-encoding or double-decoding.
37
    """
38
    pass
39
40
41
class Base64Field(models.TextField):
42
    """
43
    A subclass of TextField that encodes its data as base64 in the database.
44
    This is useful if you're dealing with unknown encodings and must guarantee
45
    that no modifications to the text occurs and that you can read/write
46
    the data in any database with any encoding.
47
    """
48
    __metaclass__ = models.SubfieldBase
49
50
    def get_db_prep_save(self, value):
51
        if isinstance(value, Base64DecodedValue):
52
            value = base64.encodestring(value)
53
54
        return super(Base64Field, self).get_db_prep_save(value)
55
56
    def to_python(self, value):
57
        if isinstance(value, Base64DecodedValue):
58
            return value
59
        else:
60
            return Base64DecodedValue(base64.decodestring(value))
30
61
31
62
32
class ModificationTimestampField(models.DateTimeField):
63
class ModificationTimestampField(models.DateTimeField):
33
    """
64
    """
34
    A subclass of DateTimeField that only auto-updates the timestamp when
65
    A subclass of DateTimeField that only auto-updates the timestamp when
  1. /trunk/djblets/djblets/util/dbevolution.py: 1 change [ new content ]
  2. /trunk/djblets/djblets/util/fields.py: 2 changes [ 1 2 ]