Skip to content

Commit

Permalink
#300 Store display context data to the related page instances (#301)
Browse files Browse the repository at this point in the history
* #300  Store display context data to related page instances

* #300  Test display rendering for different templates

* #300  Fix context processing
  • Loading branch information
duker33 authored Mar 3, 2019
1 parent 491ab61 commit 20fa1aa
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 36 deletions.
43 changes: 10 additions & 33 deletions pages/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
"""
import typing

from collections import defaultdict


class Page:
"""It's python Descriptor."""
Expand All @@ -16,55 +14,34 @@ class Page:
# Fields stored in DB. See class `pages.models.PageTemplate`
STORED = ['name', 'h1', 'keywords', 'description', 'title', 'seo_text']

def __init__(
self,
context: typing.Dict[str, typing.Any]=None,
*,
_page: 'pages.models.Page'=None,
_name='',
):
def __init__(self, page: 'pages.models.Page'=None, context: typing.Dict[str, typing.Any]=None):
"""
Pass context at ctor, but not render method,
because client code wants the same context for many different cases.
"""
self._page = page
self.key = ''
self._context = context or {}
self._page = _page
self._key = _name

def __set_name__(self, instance, name):
# get `Page` instance to create new `Page` instance with `name`
page = getattr(instance, name)
page_with_name = Page(page._context, _page=page._page, _name=name)
# Set new `Page` instance with name
setattr(instance, name, page_with_name)

def __get__(self, instance: 'pages.models.Page', type_):
if instance and self._key in instance.__dict__:
return instance.__dict__[self._key]
return Page(
{'page': instance, **self._context},
_page=instance,
_name=self._key,
instance,
{'page': instance, **instance.__dict__.get(self.key, {})}
)

def __set__(self, instance: 'pages.models.Page', value: typing.Dict[str, typing.Any]):
if not isinstance(value, dict):
raise ValueError(f'Value should be a dict')

if self._key in instance.__dict__:
# merge old context with new one
context = {**instance.__dict__[self._key]._context, **value}
else:
context = {**self._context, **value}

instance.__dict__[self._key] = Page(context, _page=instance, _name=self._key)
self._page = instance
instance.__dict__[self.key] = value

def __getattr__(self, item):
if item in self.STORED:
return self.render(item)
else:
return super().__getattribute__(item)

def __set_name__(self, owner, name):
self.key = f'_{name}_value'

def render(self, field: str):
return (
self._page.template.render_field(field, context=self._context)
Expand Down
2 changes: 1 addition & 1 deletion tests/pages/test_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class TestFields(TestCase):

def test_attribute_error(self):
# noinspection PyTypeChecker
page = display.Page({})
page = display.Page(None, {})
with self.assertRaises(AttributeError):
_ = page.bad_attr
17 changes: 15 additions & 2 deletions tests/pages/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ def test_display_attribute_uses_template(self):
)
self.assertEqual(page.display.h1, 'page h1 - template')

# @todo #SE742:30m Fix display issue with shared context.
# See the test below for details.
def test_display_has_unique_context(self):
"""Two different pages should contain not overlapping display contexts."""
left_template = PageTemplate.objects.create(name='left', h1='{{ tag }}')
Expand All @@ -146,6 +144,21 @@ def test_display_has_unique_context(self):

self.assertNotEqual(left.display.h1, right.display.h1)

def test_display_has_unique_template(self):
"""Two different pages should contain not overlapping display contexts."""
left_template = PageTemplate.objects.create(name='left', h1='{{ tag }}')
right_template = PageTemplate.objects.create(
name='right', h1='different {{ tag }}'
)
left = Page.objects.create(name='left', template=left_template)
right = Page.objects.create(name='right', template=right_template)

left.template.h1 = '{{ tag }}'
right.template.h1 = 'different {{ tag }}'
left.display, right.display = {'tag': 'A'}, {'tag': 'A'}

self.assertNotEqual(left.display.h1, right.display.h1)


class TestCustomPage(TestCase):
def test_should_get_only_custom_type_pages(self):
Expand Down

1 comment on commit 20fa1aa

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 20fa1aa Mar 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle SE742-b29cbe0a disappeared from tests/pages/test_models.py, that's why I closed #287. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

Please sign in to comment.