Alex
Alex

Reputation: 2412

Django, getting url parameter into view

I have a company model, each instance of which has a foreign_key named admin to a user.

I am writing a view to allow company admins to administer their companies:

urls.py:

path('admin/crn=<company_spec_url>', CompanyAdminView.as_view(), name="CompanyAdminView"),`

views.py:

class CompanyAdminView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
    template_name = 'company_admin.html'

    def test_func(self):
        company = Company.objects.filter(crn=context['company_spec_url'])[0]
        return company.admin == self.user

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['company'] = Company.objects.filter(crn=context['company_spec_url'])[0]
        context['announcements'] = CompanyAnnouncement.objects.filter(company__crn=context['company_spec_url'])
        return context

The get_context_data bit is working fine, the issue is in the test_func. Clearly only the company's admin should be allowed to administer a company, so I am trying to get the into the test_func, in order to test against it.

The code in test_func does not currently work, because it does not have access to context. Is it best practice to: Call super().get_context_data once, and make context a global variable so that it can be accessed from test_func - Call super().get_context_data twice, once in get_context_data and once in test_func, or something else entirely?

I've tried looking at the GET dict in the request, but it's empty. I could just parse the url within test_func to get the parameter myself, but it doesn't seem like the 'correct' way to do it.

Upvotes: 3

Views: 5241

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477606

The positional and named parameters are stored in self.args and self.kwargs respectively, so you can access it with:

class CompanyAdminView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):

    # ...

    def test_func(self):
        company = Company.objects.filter(crn=self.kwargs['company_spec_url'])[0]
        return company.admin == self.user

Note that the above can be tricky: here if multiple companies have the same crn, then you will let a (possibly random) order decide what company you pick, and whether that admin is the self.user. Furthermore it will here result in two queries.

class CompanyAdminView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):

    # ...

    def test_func(self):
        return Company.objects.filter(
            crn=self.kwargs['company_spec_url']
            admin=self.user
        ).exists()

With the above we check if there is a Company that has as crn the parameter in the URL, and self.user as admin.

Upvotes: 5

Related Questions