guardian.mixins, Generic detail view on create view?

Hello,
I’m learning RLS the django way today.
Using the djangobuilder I made a app1 with a model1, installed locally wtih django-guardian, I now have views.py:

from guardian.mixins import PermissionRequiredMixin
...
class model1CreateView(PermissionRequiredMixin, generic.CreateView):
    model = models.model1
    form_class = forms.model1Form
    permission_required = 'app1.add_model1'

also tried permission_required = 'add_app1' and permission_required = 'app1.can_add'
BTW, is there a list somewhere to know exactly the syntax for permission_required?

As you can see, it’s a create view, and app1/urls.py is:
path("app1/model1/create/", views.model1CreateView.as_view(), name="app1_model1_create"),

So I don’t get why it claims it’s a detail view and it needs a pk in the url:

Any idea?

The most common cause of situations like this is mistakenly having a second definition of the same URL in your urls.py file, or a url pattern that resolves the same way.

From the docs for the permission_required decorator:

Just like the has_perm() method, permission names take the form "<app label>.<permission codename>" (i.e. polls.add_choice for a permission on a model in the polls application).

And, the examples for the PermissionRequiredMixin shown the same syntax as being used.

Thank you @KenWhitesell !

That’s what I thought at first, but it’s coming from djangobuilder, not modified:

urlpatterns = (
    path("api/v1/", include(router.urls)),
    path("app1/model1/", views.model1ListView.as_view(), name="app1_model1_list"),
    path("app1/model1/create/", views.model1CreateView.as_view(), name="app1_model1_create"),
    path("app1/model1/detail/<int:pk>/", views.model1DetailView.as_view(), name="app1_model1_detail"),
    path("app1/model1/update/<int:pk>/", views.model1UpdateView.as_view(), name="app1_model1_update"),
    path("app1/model1/delete/<int:pk>/", views.model1DeleteView.as_view(), name="app1_model1_delete"),

    path("app1/htmx/model1/", htmx.HTMXmodel1ListView.as_view(), name="app1_model1_htmx_list"),
    path("app1/htmx/model1/create/", htmx.HTMXmodel1CreateView.as_view(), name="app1_model1_htmx_create"),
    path("app1/htmx/model1/delete/<int:pk>/", htmx.HTMXmodel1DeleteView.as_view(), name="app1_model1_htmx_delete"),
)

using the superuser, it works fine:
image

The doc is about custom permissions like polls.add_choice but doesn’t explicit the 4 main <permission codename> as in the admin/ permissions (I can’t paste a second image because I’m a new user, haha).

Meanwhile, I found it’s an old bug Can't use PermissionRequiredMixin with a CreateView · Issue #279 · django-guardian/django-guardian · GitHub
I downgraded to Django 4.0.10, and added:

    permission_required = 'app1.can_add'
    accept_global_perms = True
    def get_permission_object(self):
      return None

“The page isn’t redirecting properly”, no luck

No, that doc is about the decorator (and mixin) and how they’re used. It doesn’t matter what the source of the permissions are. All permissions (internally) are the same.

Regarding the django-guardian issue, I see you’ve added to it - hopefully someone there has an answer. Or maybe someone else here might know as well.
(We looked at it about 6 years ago and decided it didn’t satisfy our requirements. I haven’t looked at it since.)

So I didn’t get the <permission codename>:
Which one to create a new model1 in app1?
image
app1.can_add or app1.add_model1 or else?

I’m not tighted with guardian, do you know another one for RLS, to be able to only show/edit/create own user’s rows?

permission_required = ‘app1.add_model1’ is finally working, all the others threw 403
without guardian of course.
plain from django.contrib.auth.mixins import PermissionRequiredMixin

That panel doesn’t provide enough information to determine that. If you look at the Permission model, you’ll see two different fields, the “name” field and the “codename” field.

What you’re seeing in the admin is the “name” field. What you use in the decorator / mixin is the “codename” field. The two aren’t (strictly speaking) related to each other. You can’t use one to determine the value of the other.

No I don’t. The djangopackages.org site is the best place to search for them.

We did a review of what was available back around late 2016 / early 2017 and none of them were suitable for us. (Our security system allows for the permissions to be different based upon data within the row. For example, a person can edit a timesheet until it’s submitted - at which point what they can do with that timesheet changes. Also, we allow the possibility of permissions being different based upon external factors such as time-of-day or day-of-week.)

I’ve made other comments here that I believe that most RLS systems need to be customized based upon specific implementation requirements. I would expect that any third-party package is going to need to be modified for individual use, in all but the most fundamental cases.

I have to admit that, for me, Django is painful to learn.
It’s granular to depict something (name vs codename, …), but it doesn’t have an option for row level security (see your own records only) out of the box. It is safe … until you add stuff (django-components with “safer_staticfiles”), to discover that finally, it’s not safe (my ticket: safer_staticfiles working? · Issue #536 · EmilStenstrom/django-components · GitHub)
I just needed to write it out loud, not starting a rant :grin:

Sorry, thank you very much @KenWhitesell

Yes, Django is complex.

And deployment is confusing. (I’ve said multiple times that it’s probably the most confusing thing you’ll ever do with Django, because so many issues you’ll encounter don’t actually have anything to do with Django at all.)

<opinion> I’ve just looked at safer_staticfiles, and my gut reaction to that is that if this components package requires you to put either .py or non-static (template) .html files in your static directories, then I wouldn’t want to use it. </opinion>