Skip to content

Commit

Permalink
Add a mixin class for dashboard views on models with project relations (
Browse files Browse the repository at this point in the history
readthedocs#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
  • Loading branch information
agjohnson authored Aug 9, 2016
1 parent 9a870e0 commit 512654e
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
43 changes: 43 additions & 0 deletions readthedocs/projects/views/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Mixin classes for project views"""

from django.shortcuts import get_object_or_404

from readthedocs.projects.models import Project


class ProjectRelationMixin(object):

"""Mixin class for constructing model views for project dashboard
This mixin class is used for model views on models that have a relation
to the :py:cls:`Project` model.
:cvar project_lookup_url_kwarg: URL kwarg to use in project lookup
:cvar project_lookup_field: Query field for project relation
:cvar project_context_object_name: Context object name for project
"""

project_lookup_url_kwarg = 'project_slug'
project_lookup_field = 'project'
project_context_object_name = 'project'

def get_project_queryset(self):
return Project.objects.for_admin_user(user=self.request.user)

def get_project(self):
if self.project_lookup_url_kwarg not in self.kwargs:
return None
return get_object_or_404(
self.get_project_queryset(),
slug=self.kwargs[self.project_lookup_url_kwarg]
)

def get_queryset(self):
return self.model.objects.filter(
**{self.project_lookup_field: self.get_project()}
)

def get_context_data(self, **kwargs):
context = super(ProjectRelationMixin, self).get_context_data(**kwargs)
context[self.project_context_object_name] = self.get_project()
return context
27 changes: 26 additions & 1 deletion readthedocs/rtd_tests/tests/test_project_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
from django.test import TestCase
from django.contrib.auth.models import User
from django.contrib.messages import constants as message_const
from django.views.generic.base import ContextMixin
from django_dynamic_fixture import get
from django_dynamic_fixture import new

from readthedocs.core.models import UserProfile
from readthedocs.rtd_tests.base import (WizardTestCase, MockBuildTestCase,
RequestFactoryTestMixin)
from readthedocs.projects.exceptions import ProjectSpamError
from readthedocs.projects.models import Project
from readthedocs.projects.models import Project, Domain
from readthedocs.projects.views.private import ImportWizardView
from readthedocs.projects.views.mixins import ProjectRelationMixin


@patch('readthedocs.projects.views.private.trigger_build', lambda x, basic: None)
Expand Down Expand Up @@ -330,3 +332,26 @@ def test_delete_project(self):
remove_dir.apply_async.assert_called_with(
queue='celery',
args=[project.doc_path])


class TestPrivateMixins(MockBuildTestCase):

def setUp(self):
self.project = get(Project, slug='kong')
self.domain = get(Domain, project=self.project)

def test_project_relation(self):
"""Class using project relation mixin class"""

class FoobarView(ProjectRelationMixin, ContextMixin):
model = Domain

def get_project_queryset(self):
# Don't test this as a view with a request.user
return Project.objects.all()

view = FoobarView()
view.kwargs = {'project_slug': 'kong'}
self.assertEqual(view.get_project(), self.project)
self.assertEqual(view.get_queryset().first(), self.domain)
self.assertEqual(view.get_context_data()['project'], self.project)

0 comments on commit 512654e

Please sign in to comment.