Skip to content

Commit 512654e

Browse files
authored
Add a mixin class for dashboard views on models with project relations (#2353)
* Add a mixin class for dashboard views on models with project relations As we overhaul the project admin dashboard, a good amount of code can be cleaned up by using a CBV rather than repeating the view code like is currently used. I had a need for this outside this code base, but implemented it here instead. Views would look like: class DomainMixin(ProjectRelationMixin): model = Domain lookup_url_kwarg = 'pk' class ListDomainView(DomainMixin, ListView): pass class DetailDomainView(DomainMixin, DetailView): pass Views would then have access to a `project` and `domains` in template context data. * Alter pattern for ProjectRelationMixin and context data
1 parent 9a870e0 commit 512654e

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

readthedocs/projects/views/mixins.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Mixin classes for project views"""
2+
3+
from django.shortcuts import get_object_or_404
4+
5+
from readthedocs.projects.models import Project
6+
7+
8+
class ProjectRelationMixin(object):
9+
10+
"""Mixin class for constructing model views for project dashboard
11+
12+
This mixin class is used for model views on models that have a relation
13+
to the :py:cls:`Project` model.
14+
15+
:cvar project_lookup_url_kwarg: URL kwarg to use in project lookup
16+
:cvar project_lookup_field: Query field for project relation
17+
:cvar project_context_object_name: Context object name for project
18+
"""
19+
20+
project_lookup_url_kwarg = 'project_slug'
21+
project_lookup_field = 'project'
22+
project_context_object_name = 'project'
23+
24+
def get_project_queryset(self):
25+
return Project.objects.for_admin_user(user=self.request.user)
26+
27+
def get_project(self):
28+
if self.project_lookup_url_kwarg not in self.kwargs:
29+
return None
30+
return get_object_or_404(
31+
self.get_project_queryset(),
32+
slug=self.kwargs[self.project_lookup_url_kwarg]
33+
)
34+
35+
def get_queryset(self):
36+
return self.model.objects.filter(
37+
**{self.project_lookup_field: self.get_project()}
38+
)
39+
40+
def get_context_data(self, **kwargs):
41+
context = super(ProjectRelationMixin, self).get_context_data(**kwargs)
42+
context[self.project_context_object_name] = self.get_project()
43+
return context

readthedocs/rtd_tests/tests/test_project_views.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
from django.test import TestCase
55
from django.contrib.auth.models import User
66
from django.contrib.messages import constants as message_const
7+
from django.views.generic.base import ContextMixin
78
from django_dynamic_fixture import get
89
from django_dynamic_fixture import new
910

1011
from readthedocs.core.models import UserProfile
1112
from readthedocs.rtd_tests.base import (WizardTestCase, MockBuildTestCase,
1213
RequestFactoryTestMixin)
1314
from readthedocs.projects.exceptions import ProjectSpamError
14-
from readthedocs.projects.models import Project
15+
from readthedocs.projects.models import Project, Domain
1516
from readthedocs.projects.views.private import ImportWizardView
17+
from readthedocs.projects.views.mixins import ProjectRelationMixin
1618

1719

1820
@patch('readthedocs.projects.views.private.trigger_build', lambda x, basic: None)
@@ -330,3 +332,26 @@ def test_delete_project(self):
330332
remove_dir.apply_async.assert_called_with(
331333
queue='celery',
332334
args=[project.doc_path])
335+
336+
337+
class TestPrivateMixins(MockBuildTestCase):
338+
339+
def setUp(self):
340+
self.project = get(Project, slug='kong')
341+
self.domain = get(Domain, project=self.project)
342+
343+
def test_project_relation(self):
344+
"""Class using project relation mixin class"""
345+
346+
class FoobarView(ProjectRelationMixin, ContextMixin):
347+
model = Domain
348+
349+
def get_project_queryset(self):
350+
# Don't test this as a view with a request.user
351+
return Project.objects.all()
352+
353+
view = FoobarView()
354+
view.kwargs = {'project_slug': 'kong'}
355+
self.assertEqual(view.get_project(), self.project)
356+
self.assertEqual(view.get_queryset().first(), self.domain)
357+
self.assertEqual(view.get_context_data()['project'], self.project)

0 commit comments

Comments
 (0)