Skip to content

Permissions system: Expand the owner_field system

Currently, on every model we can set an owner_field which point to a field of the model containing a single user. This user will have some preset of permission defined by the owner_perms meta property.

from django.contrib.auth import get_user_model
from django.db import models
from djangoldp.models import Model

class SomeModel(Model):
    owner = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, blank=True,)

    class Meta(Model.Meta):
        anonymous_perms = ["view"]
        authenticated_perms = ["inherit", "add"]
        auto_author = "owner"
        owner_field = "owner"
        owner_perms = ["inherit", "change", "delete"]

Problem: Whenever I write a model with a foreign key to a "parent" model, I have to write complex custom permissions where I should be able to grab a field value from the targeted model, like its own owner_field.

I'd need to expand this owner_field functionality to allow model with foreign keys to this model to use the same owner field.

Two solution came to my mind:

  1. owner_field = "some_model.owner" : Manually set the target field, will follow the foreign key and take the targeted field value as owner.
  2. owner_field = "some_model" : Automatically use the meta.owner_field of the targeted foreign key model.

Both would cover my use case. Second feels easier to read. First is more extensive.

from django.contrib.auth import get_user_model
from django.db import models
from djangoldp.models import Model

class SomeModel(Model):
    owner = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, blank=True,)

    class Meta(Model.Meta):
        anonymous_perms = ["view"]
        authenticated_perms = ["inherit", "add"]
        auto_author = "owner"
        owner_field = "owner"
        owner_perms = ["inherit", "change", "delete"]


class SomeSubModel(Model):
    some_model = models.ForeignKey(SomeModel, on_delete=models.CASCADE, related_name="some_submodel", null=True, blank=True,)

    class Meta(Model.Meta):
        anonymous_perms = ["view"]
        authenticated_perms = ["inherit"]
        owner_field = "some_model.owner" # <- Solution 1 : Manually set the field on target foreign key
        # owner_field = "some_model" # <- Solution 2 : Automatically grab the foreign key `$.meta.owner_field``
        owner_perms = ["inherit", "add", "change", "delete"]

Notice that "submodel" is an inaccurate name, as a foreign key would allow a two-way definition of this owner. Solution 2 mean that circular declaration would crash, it's fine, warn the user should be enough. Solution 1 may allow some weird pathing like SomeSubModel.meta.owner_field = "some_model.different_owner" + SomeModel.meta.owner_field = "some_submodel.owner", I think that if this solution is chosen, we may need it to work or at least warn the developer that this feature is unsupported.

Both solutions fits me. Advice welcomed & estimation required @calummackervoy (time estimation, no need for token conversion)