Skip to content

Instantly share code, notes, and snippets.

@kbussell
Last active April 5, 2016 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kbussell/1fae1a58aa5d427e458007583e5229a1 to your computer and use it in GitHub Desktop.
Save kbussell/1fae1a58aa5d427e458007583e5229a1 to your computer and use it in GitHub Desktop.
from django.db import models
from django.utils.functional import curry
class PrivateFieldDescriptor(object):
def __init__(self, field):
self.field = field
def __get__(self, instance, type=None):
if instance is None:
raise AttributeError('Can only be accessed via an instance.')
return self.field.get_value(instance)
def __set__(self, instance, value):
if self.field.name in instance.__dict__:
raise AttributeError(
'Direct {0} modification is not allowed'.format(self.field.name))
self.field.set_value(instance, value)
def field_setter_func(instance, value, field):
return field.set_value(instance, value)
class PrivateFieldMixin(object):
descriptor_class = PrivateFieldDescriptor
def get_value(self, instance):
return instance.__dict__[self.name]
def set_value(self, instance, state):
instance.__dict__[self.name] = state
def contribute_to_class(self, cls, name, virtual_only=False):
self.base_cls = cls
super(PrivateFieldMixin, self).contribute_to_class(cls, name, virtual_only=virtual_only)
setattr(cls, self.name, self.descriptor_class(self))
setattr(cls, 'set_' + self.name, curry(field_setter_func, field=self))
class PrivateCharField(PrivateFieldMixin, models.CharField):
pass
class SomeModel(models.Model):
private_field = PrivateCharField(max_length=64)
def do_something(self, pub, priv):
self.set_private_field(priv)
self.save()
from django.test import TestCase
from django_private_field.private_field.models import SomeModel
class ModelTest(TestCase):
def test_set(self):
m = SomeModel()
m.set_private_field('private!!')
m.save()
m = SomeModel.objects.first()
self.assertEqual(m.private_field, 'private!!')
def test_direct_set(self):
m = SomeModel()
with self.assertRaises(AttributeError):
m.private_field = 'Fail'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment