Read only fields in models
Supposing you have a field in your model and you don't want it to be changed, ever.
How would you do that? Well actually you can't from Django, which we'll see in a minute. Here's a script that should work for most people. Basically, set up a signal (or a custom save method) so that when your object is saved it compares the old to new and then figures out if it can be changed.
from django.db import models
class BankAccount(models.Model):
amount = models.DecimalField(max_digits=20, decimal_places=2)
number = models.CharField(max_length=10)
read_only = ("number",)
def read_only(sender, instance, **kw):
if instance.id:
old = sender.objects.get(id=instance.id)
for field in sender.read_only:
if (getattr(old, field) != getattr(instance, field)):
raise ValueError, "The field %s cannot be changed, once set, ever." % field
models.signals.pre_save.connect(read_only, sender=BankAccount)
On a save, we look up the read_only attribute and see if any of those fields have changed and raise an error if they do. In this scenario, you can change the amount of money in a bank account, but the number of the account will not change once set.
Here's a test to check it works:
from django.test import TestCase
from models import BankAccount
from decimal import Decimal
class tests(TestCase):
def testReadOnly(self):
bank = BankAccount()
bank.number = "1234567890"
bank.amount = Decimal("100.00")
bank.save()
id = bank.id
bank.amount = Decimal("200.00")
bank.save()
bank.number = "9999999999"
self.assertRaises(ValueError, bank.save)
This is awfully close to model validation. Something that Django doesn't have yet. And it there's two areas it can break down.
- When someone writes raw SQL.
- The update method on a QuerySet does not call the signal or the custom save method. For example:
# Warning does not work with update
BankAccount.objects.all().update(number="999999999")
# eeek!
assert BankAccount.objects.get(id=id).number == "999999999"
This is discussed here and here. I wonder if it's worth going any further on this until model validation comes along. Perhaps not.
Comments
There are no comments.
Login to add comments

