3

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.

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this. The crn is actually unique, but the second option is much better, as it catches the case in which the given crn doesn't exist. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.