26

Is it possible to make a Django model read only? No creating, updating etc.

N.B. this question is different to:

Make a Django model read-only? (this question allows creation of new records)

Whole model as read-only (only concerns the Django admin interface - I'd like the model to be read only throughout the whole app)

Mark Chackerian
  • 21,866
  • 6
  • 108
  • 99
Ollie Glass
  • 19,455
  • 21
  • 76
  • 107

3 Answers3

31

Override the save and delete methods for the model. How are you planning to add objects to your model?

def save(self, *args, **kwargs):
     return

def delete(self, *args, **kwargs):
     return
Mikael
  • 3,148
  • 22
  • 20
  • 2
    "How are you planning to add objects to your model?" -> Probably in pure sql, or from another webapp. – jpic Aug 28 '12 at 11:40
  • OK, the above should work then. If you want to you can also raise an exception if someone tries to save/delete the model. – Mikael Aug 28 '12 at 11:41
  • 17
    FWIW, you would also need to define a custom manager to protect the `create`, `update`, and `delete` methods there as well. – Chris Pratt Aug 28 '12 at 15:39
  • 8
    "How are you planning to add objects to your model?" -> Sometimes it's very convenient to map unmanaged model to database view, but not table. – Alexey Sidash Aug 04 '16 at 07:51
15

Database Routers

To take more precautions that your model is read-only, you can use the DATABASE_ROUTERS setting to disable writing on a per model basis:

# settings.py
DATABASE_ROUTERS = ('dbrouters.MyCustomRouter', )


# dbrouters.py
class MyCustomRouter(object):
    def db_for_write(self, model, **hints):
        if model == MyReadOnlyModel:
            raise Exception("This model is read only. Shame!")
        return None

I would consider this an insurance policy, and not the primary way to solve the problem. Mikael's answer, for example, is great but doesn't cover all cases because some Django operations bypass delete and save methods.

See Juan José Brown's answer in Django - how to specify a database for a model? for a more detailed description of using a database router.

Setting permissions on database user

However, even the database router approach seems to have loopholes, i.e. there are ways to send SQL from Django that bypasses your router code. To be absolutely sure of making something readonly, you should set the permissions on the database user. This question describes how to set up a readonly postgreql user, which could then be the database user set by Django in settings.DATABASES.

Mark Chackerian
  • 21,866
  • 6
  • 108
  • 99
-5

You can set managed = False in your model's Meta:

from django.db import models

class MyReadOnlyModel(models.Model):
    class Meta:
        managed = False

If False, no database table creation or deletion operations will be performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means.

https://docs.djangoproject.com/en/dev/ref/models/options/#managed

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
maxsocl
  • 484
  • 3
  • 9