Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative to RulesModelBase in DRF to manage dependency on this library. #155

Open
sergioisidoro opened this issue Dec 22, 2021 · 8 comments

Comments

@sergioisidoro
Copy link
Contributor

sergioisidoro commented Dec 22, 2021

I'm working on a Django DRF project, and while implementing the rules, I feel like inheriting from RulesModelBase creates a really heavy dependency on this library.

I'm trying to make it so that the rules dependency only affects the views, and not go all the way to the models.

From what I can gather, the views have access to the current user, and the objects. The predicates get both the user and the permission object as parameters, so it feels like it would be possible.

Has anyone dealt with similar issues than this?

https://github.com/dfunckt/django-rules#permissions-in-django-rest-framework

Of course, it also requires you to declare your models as described in Permissions in models.

@sergioisidoro sergioisidoro changed the title Alternative to RulesModelBase to manage coupling and dependency on this library. Alternative to RulesModelBase in DRF to manage dependency on this library. Dec 22, 2021
@sergioisidoro
Copy link
Contributor Author

After checking AutoPermissionViewSetMixin it seems that its only dependency is get_perm in:

perm = self.get_queryset().model.get_perm(perm_type)

which simply returns return "%s.%s_%s" % (cls._meta.app_label, perm_type, cls._meta.model_name)

It seems this dependency could be easily isolated into a util class.

def get_permission_from_class(cls, perm_type):
   return "%s.%s_%s" % (cls._meta.app_label, perm_type, cls._meta.model_name)

Which would make AutoPermissionViewSetMixin independent of the Mixin, as long as the rules are loaded (or autoloaded) according to the naming convention. Am I missing something? Would this be a reasonable change?

@dfunckt
Copy link
Owner

dfunckt commented Dec 22, 2021

Yes, I'd happily accept such a change. However, is it possible to abstract away the whole self.get_queryset().model.get_perm(perm_type) call? I'd rather not hardcode into Rules how perm names are constructed, but provide hooks for clients to override reasonable defaults instead.

@sergioisidoro
Copy link
Contributor Author

sergioisidoro commented Dec 22, 2021

@dfunckt if we define it in AutoPermissionViewSetMixin, the user can override it by creating:

class MyAutoPermissionViewSetMixin(AutoPermissionViewSetMixin):
   def get_permission_form_model(self, class, perm):
       return "custom permission string"

This would be a breaking change, however, so we need to continue supporting the model mixin. I'm wondering is something like this could work:

        model = self.get_queryset().model
        try:
            use_mixin_method = callable(model.get_perm)
        except AttributeError:
            use_mixin_method = False

        if use_mixin_method:
            perm = model.get_perm(perm_type)
        else:
            perm = self.get_permission_form_model(model, perm_type)

And here there's the issue of precedence. For now the model mixin would have precedence to avoid any breaking changes.

@dfunckt
Copy link
Owner

dfunckt commented Dec 22, 2021

Sorry, I must be missing something -- why is it a breaking change?

I'll need to look into the code, but from this discussion I understand that if AutoPermissionViewSetMixin was like:

class AutoPermissionViewSetMixin:
  # ...

  def get_permission_form_model(self, class, perm):
    return self.get_queryset().model.get_perm(perm_type)

existing clients would not break. What do I miss?

@sergioisidoro
Copy link
Contributor Author

sergioisidoro commented Dec 22, 2021

That option still keeps the dependency, although yes, it makes it much easier to move around it

My idea was to take it a step further, and by default, remove the dependency of the Views and DRF Mixins from the RulesModelMixin, and make it fully optional. That could break things if people have already made their custom Model get_perm.

Your suggestion already fulfils my biggest issue, so I would be happy with it :)


Heres a bit more detail about the idea I had, with some iterations based on our discussion and being backwards compatible:

# All auto permission mixins (both for DRF and Django views) inherit from this mixin
class BaseAutoPermissionMixin:

  def get_perm(self, class, perm_type):
      return "%s.%s_%s" % (class._meta.app_label, perm_type, class._meta.model_name)

  def get_permission_for_model(self, model, perm_type):
        try:
            use_model_mixin_method = callable(model.get_perm)
        except AttributeError:
            use_model_mixin_method = False

        if use_model_mixin_method:
            perm = model.get_perm(perm_type)
        else:
            perm = self.get_perm(model, perm_type)
         return perm

# For DRF
class AutoPermissionViewSetMixin(BaseAutoPermissionMixin):
  # ...

# For views
class AutoPermissionRequiredMixin(PermissionRequiredMixin, BaseAutoPermissionMixin)

@dfunckt
Copy link
Owner

dfunckt commented Dec 22, 2021

Okay, I totally see the use-case and agree in principle that this would be great to have but I need to spend some time to check the existing code and your proposal in more depth. If you're keen to PR stuff in the meantime, feel free and we'll take it from there.

@sergioisidoro
Copy link
Contributor Author

Sure, I'll post a PR for this. Actually maybe I can make 2:

  • One PR, which is the simplest, to abstract the get_permission_form_model making it overridable in the mixin
  • Another PR based on the first one with these larger changes.

We can move the discussion there as well, since it's easier to discuss things with concrete code :)

Thanks for taking the time and attention on this! Really appreciate it!

@sergioisidoro
Copy link
Contributor Author

@dfunckt The PRs should be read for a first review.
Let me know if there is anything else you would like me to do or followup regarding this topic :)
Thanks for your help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants