django-siteblocks 1.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_siteblocks-1.2.2.dist-info/METADATA +87 -0
- django_siteblocks-1.2.2.dist-info/RECORD +21 -0
- django_siteblocks-1.2.2.dist-info/WHEEL +4 -0
- django_siteblocks-1.2.2.dist-info/licenses/LICENSE +27 -0
- siteblocks/__init__.py +4 -0
- siteblocks/admin.py +31 -0
- siteblocks/apps.py +10 -0
- siteblocks/locale/en/LC_MESSAGES/django.po +98 -0
- siteblocks/locale/fr/LC_MESSAGES/django.mo +0 -0
- siteblocks/locale/fr/LC_MESSAGES/django.po +105 -0
- siteblocks/locale/ru/LC_MESSAGES/django.mo +0 -0
- siteblocks/locale/ru/LC_MESSAGES/django.po +108 -0
- siteblocks/migrations/0001_initial.py +29 -0
- siteblocks/migrations/0002_auto_20140921_1038.py +26 -0
- siteblocks/migrations/0003_alter_block_access_guest_alter_block_access_loggedin.py +23 -0
- siteblocks/migrations/__init__.py +0 -0
- siteblocks/models.py +41 -0
- siteblocks/settings.py +5 -0
- siteblocks/siteblocksapp.py +224 -0
- siteblocks/templatetags/__init__.py +0 -0
- siteblocks/templatetags/siteblocks.py +60 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: django-siteblocks
|
|
3
|
+
Version: 1.2.2
|
|
4
|
+
Summary: Reusable application for Django introducing URL-dependent static and dynamic data blocks
|
|
5
|
+
Project-URL: Homepage, https://github.com/idlesign/django-siteblocks
|
|
6
|
+
Project-URL: Documentation, https://django-siteblocks.readthedocs.io/
|
|
7
|
+
Author-email: Igor Starikov <idlesign@yandex.ru>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: Django,blocks
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# django-siteblocks
|
|
28
|
+
|
|
29
|
+
<https://github.com/idlesign/django-siteblocks>
|
|
30
|
+
|
|
31
|
+
[](https://pypi.python.org/pypi/django-siteblocks)
|
|
32
|
+
[](https://pypi.python.org/pypi/django-siteblocks)
|
|
33
|
+
[](https://coveralls.io/r/idlesign/django-siteblocks)
|
|
34
|
+
|
|
35
|
+
## What's that
|
|
36
|
+
|
|
37
|
+
*django-siteblocks is a reusable application for Django to build blocks of static or dynamic data that could be used in templates.*
|
|
38
|
+
|
|
39
|
+
It allows you to describe data that doesn't clearly belong to any application in your project in terms of static or dynamic blocks,
|
|
40
|
+
that could be rendered in certain places on site pages. These blocks are addressed in templates by their aliases.
|
|
41
|
+
|
|
42
|
+
The following siteblock types are supported:
|
|
43
|
+
|
|
44
|
+
### Static
|
|
45
|
+
|
|
46
|
+
Those are defined using Django Admin contrib and are linked to certain URLs.
|
|
47
|
+
|
|
48
|
+
This allows different siteblock contents on different URLs. Just go to admin and add some blocks.
|
|
49
|
+
|
|
50
|
+
### Dynamic
|
|
51
|
+
|
|
52
|
+
Those are ordinary Python functions registered as siteblocks returning contents.
|
|
53
|
+
|
|
54
|
+
This allows complex logic to build siteblock contents. Let's make a block with a random quote from Pratchett:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from random import choice
|
|
58
|
+
|
|
59
|
+
from siteblocks.siteblocksapp import register_dynamic_block
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_quote(**kwargs):
|
|
63
|
+
quotes = [
|
|
64
|
+
'Early to rise, early to bed, makes a man healthy, wealthy and dead.',
|
|
65
|
+
'The duke had a mind that ticked like a clock and, like a clock, it regularly went cuckoo.',
|
|
66
|
+
'Speak softly and employ a huge man with a crowbar.',
|
|
67
|
+
]
|
|
68
|
+
return choice(quotes)
|
|
69
|
+
|
|
70
|
+
register_dynamic_block('quote', get_quote)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Block rendering
|
|
74
|
+
|
|
75
|
+
Use `siteblocks` tag to render block contents where you need it.
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
{% load siteblocks %}
|
|
79
|
+
|
|
80
|
+
<div class="quote">
|
|
81
|
+
{% siteblock "quote" %}
|
|
82
|
+
</div>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
<https://django-siteblocks.readthedocs.io/>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
siteblocks/__init__.py,sha256=QFqUvdnuC8ebmxSfLeY1iXn6kxj_ekIGviPOPfQQFGg,76
|
|
2
|
+
siteblocks/admin.py,sha256=aaE1CHDf_hTXM6wq4qM-NIIy4tRGPG9HRXexf9iblxw,744
|
|
3
|
+
siteblocks/apps.py,sha256=7s4IncuqsRvJsjPfVWP20radBQJ1qOoMxyEZMOriiH4,277
|
|
4
|
+
siteblocks/models.py,sha256=PgSJWPE6Ngix2_VDImPsftwtB6aKwALE-_E5Aobdunc,1589
|
|
5
|
+
siteblocks/settings.py,sha256=JBMnc2kqgmMchrp-TOhQqhTsehbRsxKMdRl6nW8I2rE,152
|
|
6
|
+
siteblocks/siteblocksapp.py,sha256=b_JpSdDETSUDKKpewBv099f97qOOGAiV1X1vnj9-Lao,7597
|
|
7
|
+
siteblocks/locale/en/LC_MESSAGES/django.po,sha256=21aqqDyGDRnJq5EBzerd5g0ouVuMG55lCgNNoDBPjEs,1927
|
|
8
|
+
siteblocks/locale/fr/LC_MESSAGES/django.mo,sha256=orsVIt75ULgsFsw6xZMKUUGQ5cYQMpIZGk0fNV8DjHQ,1771
|
|
9
|
+
siteblocks/locale/fr/LC_MESSAGES/django.po,sha256=FN5t8AjXS3Yb0uxQCHPzXR_S-faVEavREyMvymG6v90,2645
|
|
10
|
+
siteblocks/locale/ru/LC_MESSAGES/django.mo,sha256=gv6Eg-xMHCFU2RAXgSautwYkX7dKIpQfb9aoPNCJIng,3015
|
|
11
|
+
siteblocks/locale/ru/LC_MESSAGES/django.po,sha256=PB0CciHQjiAhAThpdtfxTjHdnP4VpM_NhsWNVqW6G1c,3533
|
|
12
|
+
siteblocks/migrations/0001_initial.py,sha256=ZP1YSNFu0RCatiNEobUO2Fw93SJHWAsHpW7P8Mt7krU,1522
|
|
13
|
+
siteblocks/migrations/0002_auto_20140921_1038.py,sha256=H9mN6sdeiYSHdHyyJMcOzIxbDlzvcZBrDcUoBGCWbJI,868
|
|
14
|
+
siteblocks/migrations/0003_alter_block_access_guest_alter_block_access_loggedin.py,sha256=1QdRvNrx4Na-8g7CaV9whhcncWbQPBQV9ofwPTI3sjU,799
|
|
15
|
+
siteblocks/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
siteblocks/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
siteblocks/templatetags/siteblocks.py,sha256=F-RBs3J-hzMDYxH8vr9fsTAEHI-LC06hCgkG66XgYKM,1691
|
|
18
|
+
django_siteblocks-1.2.2.dist-info/METADATA,sha256=g7lTTyzKtzAJl3O2lrQJyr7HadzEy9XYZjB9jT-uRkQ,3080
|
|
19
|
+
django_siteblocks-1.2.2.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
20
|
+
django_siteblocks-1.2.2.dist-info/licenses/LICENSE,sha256=TgZMEIuVqPzFCn8S6twEoSSGSgFF2-2oaKWrgULpEOA,1555
|
|
21
|
+
django_siteblocks-1.2.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2010-2026, Igor 'idle sign' Starikov
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. Neither the name of the django-siteblocks nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
19
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
20
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
22
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
23
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
24
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
25
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
siteblocks/__init__.py
ADDED
siteblocks/admin.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
|
+
|
|
4
|
+
from .models import Block
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BlockAdmin(admin.ModelAdmin):
|
|
8
|
+
|
|
9
|
+
list_display = ('alias', 'description', 'url', 'hidden', 'access_loggedin', 'access_guest')
|
|
10
|
+
|
|
11
|
+
search_fields = ['alias', 'url']
|
|
12
|
+
|
|
13
|
+
list_filter = ['hidden']
|
|
14
|
+
|
|
15
|
+
ordering = ['alias']
|
|
16
|
+
|
|
17
|
+
fieldsets = (
|
|
18
|
+
(_('Basic settings'), {
|
|
19
|
+
'fields': ('alias', 'url', 'contents',)
|
|
20
|
+
}),
|
|
21
|
+
(_('Access settings'), {
|
|
22
|
+
'classes': ('collapse',),
|
|
23
|
+
'fields': ('access_loggedin', 'access_guest')
|
|
24
|
+
}),
|
|
25
|
+
(_('Additional settings'), {
|
|
26
|
+
'fields': ('description', 'hidden')
|
|
27
|
+
}),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
admin.site.register(Block, BlockAdmin)
|
siteblocks/apps.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from django.apps import AppConfig
|
|
2
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SiteblocksConfig(AppConfig):
|
|
6
|
+
"""Siteblocks configuration."""
|
|
7
|
+
|
|
8
|
+
name = 'siteblocks'
|
|
9
|
+
verbose_name = _('Site Blocks')
|
|
10
|
+
default_auto_field = 'django.db.models.AutoField'
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
5
|
+
#
|
|
6
|
+
#, fuzzy
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2014-09-21 12:39+0700\n"
|
|
12
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
|
+
"Language: \n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
|
|
20
|
+
#: admin.py:14
|
|
21
|
+
msgid "Basic settings"
|
|
22
|
+
msgstr ""
|
|
23
|
+
|
|
24
|
+
#: admin.py:17
|
|
25
|
+
msgid "Access settings"
|
|
26
|
+
msgstr ""
|
|
27
|
+
|
|
28
|
+
#: admin.py:21
|
|
29
|
+
msgid "Additional settings"
|
|
30
|
+
msgstr ""
|
|
31
|
+
|
|
32
|
+
#: config.py:9 models.py:19
|
|
33
|
+
msgid "Site Blocks"
|
|
34
|
+
msgstr ""
|
|
35
|
+
|
|
36
|
+
#: models.py:9
|
|
37
|
+
msgid "Alias"
|
|
38
|
+
msgstr ""
|
|
39
|
+
|
|
40
|
+
#: models.py:9
|
|
41
|
+
msgid "Short name to address this block from a template."
|
|
42
|
+
msgstr ""
|
|
43
|
+
|
|
44
|
+
#: models.py:10
|
|
45
|
+
msgid "Description"
|
|
46
|
+
msgstr ""
|
|
47
|
+
|
|
48
|
+
#: models.py:10
|
|
49
|
+
msgid "Short memo for this block."
|
|
50
|
+
msgstr ""
|
|
51
|
+
|
|
52
|
+
#: models.py:11
|
|
53
|
+
msgid "URL"
|
|
54
|
+
msgstr ""
|
|
55
|
+
|
|
56
|
+
#: models.py:11
|
|
57
|
+
msgid ""
|
|
58
|
+
"Page URL this block is related to. Regular expressions supported (e.g.: \"/"
|
|
59
|
+
"news.*\" — everything under \"/news\").<br />View names are supported: "
|
|
60
|
+
"prepend <b>:</b> to view name <br /><b>Reserved URL alias:</b> \"*\" — "
|
|
61
|
+
"every page."
|
|
62
|
+
msgstr ""
|
|
63
|
+
|
|
64
|
+
#: models.py:12
|
|
65
|
+
msgid "Contents"
|
|
66
|
+
msgstr ""
|
|
67
|
+
|
|
68
|
+
#: models.py:12
|
|
69
|
+
msgid "Block contents to render in a template."
|
|
70
|
+
msgstr ""
|
|
71
|
+
|
|
72
|
+
#: models.py:13
|
|
73
|
+
msgid "Logged in only"
|
|
74
|
+
msgstr ""
|
|
75
|
+
|
|
76
|
+
#: models.py:13
|
|
77
|
+
msgid "Check it to grant access to this block to authenticated users only."
|
|
78
|
+
msgstr ""
|
|
79
|
+
|
|
80
|
+
#: models.py:14
|
|
81
|
+
msgid "Guests only"
|
|
82
|
+
msgstr ""
|
|
83
|
+
|
|
84
|
+
#: models.py:14
|
|
85
|
+
msgid "Check it to grant access to this block to guests only."
|
|
86
|
+
msgstr ""
|
|
87
|
+
|
|
88
|
+
#: models.py:15
|
|
89
|
+
msgid "Hidden"
|
|
90
|
+
msgstr ""
|
|
91
|
+
|
|
92
|
+
#: models.py:15
|
|
93
|
+
msgid "Whether to show this block when requested."
|
|
94
|
+
msgstr ""
|
|
95
|
+
|
|
96
|
+
#: models.py:18
|
|
97
|
+
msgid "Site Block"
|
|
98
|
+
msgstr ""
|
|
Binary file
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
#
|
|
5
|
+
# Translators:
|
|
6
|
+
# PatrickHetu <patrick.hetu@gmail.com>, 2014
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: django-siteblocks\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2014-09-21 12:39+0700\n"
|
|
12
|
+
"PO-Revision-Date: 2014-09-21 05:35+0000\n"
|
|
13
|
+
"Last-Translator: Igor Starikov <idlesign@yandex.ru>\n"
|
|
14
|
+
"Language-Team: French (http://www.transifex.com/projects/p/django-siteblocks/"
|
|
15
|
+
"language/fr/)\n"
|
|
16
|
+
"Language: fr\n"
|
|
17
|
+
"MIME-Version: 1.0\n"
|
|
18
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
19
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
20
|
+
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
|
21
|
+
|
|
22
|
+
#: admin.py:14
|
|
23
|
+
msgid "Basic settings"
|
|
24
|
+
msgstr ""
|
|
25
|
+
|
|
26
|
+
#: admin.py:17
|
|
27
|
+
msgid "Access settings"
|
|
28
|
+
msgstr ""
|
|
29
|
+
|
|
30
|
+
#: admin.py:21
|
|
31
|
+
msgid "Additional settings"
|
|
32
|
+
msgstr ""
|
|
33
|
+
|
|
34
|
+
#: config.py:9 models.py:19
|
|
35
|
+
msgid "Site Blocks"
|
|
36
|
+
msgstr "Site Blocks"
|
|
37
|
+
|
|
38
|
+
#: models.py:9
|
|
39
|
+
msgid "Alias"
|
|
40
|
+
msgstr "Jeton"
|
|
41
|
+
|
|
42
|
+
#: models.py:9
|
|
43
|
+
msgid "Short name to address this block from a template."
|
|
44
|
+
msgstr "Nom court du jeton à remplacer dans le gabarit."
|
|
45
|
+
|
|
46
|
+
#: models.py:10
|
|
47
|
+
msgid "Description"
|
|
48
|
+
msgstr "Description"
|
|
49
|
+
|
|
50
|
+
#: models.py:10
|
|
51
|
+
msgid "Short memo for this block."
|
|
52
|
+
msgstr "Description courte pour ce jeton."
|
|
53
|
+
|
|
54
|
+
#: models.py:11
|
|
55
|
+
msgid "URL"
|
|
56
|
+
msgstr "URL"
|
|
57
|
+
|
|
58
|
+
#: models.py:11
|
|
59
|
+
msgid ""
|
|
60
|
+
"Page URL this block is related to. Regular expressions supported (e.g.: \"/"
|
|
61
|
+
"news.*\" — everything under \"/news\").<br />View names are supported: "
|
|
62
|
+
"prepend <b>:</b> to view name <br /><b>Reserved URL alias:</b> \"*\" — "
|
|
63
|
+
"every page."
|
|
64
|
+
msgstr ""
|
|
65
|
+
"URL, nom d'une vue ou expressions régulières des pages dans lesquelles le "
|
|
66
|
+
"jeton sera remplacé. <br />Par exemple:<br /> \"/nouvelles.*\" — "
|
|
67
|
+
"remplacera toutes les pages qui commençant par \"/nouvelles\").<br />Le nom "
|
|
68
|
+
"d'une vue est aussi supporté avec le préfixe <b>:</b><br /><b>Utiliser "
|
|
69
|
+
"l'astérisque </b> \"*\" — pour indiquer toutes les pages."
|
|
70
|
+
|
|
71
|
+
#: models.py:12
|
|
72
|
+
msgid "Contents"
|
|
73
|
+
msgstr "Contenu"
|
|
74
|
+
|
|
75
|
+
#: models.py:12
|
|
76
|
+
msgid "Block contents to render in a template."
|
|
77
|
+
msgstr "Contenu à inclure dans le gabarit."
|
|
78
|
+
|
|
79
|
+
#: models.py:13
|
|
80
|
+
msgid "Logged in only"
|
|
81
|
+
msgstr ""
|
|
82
|
+
|
|
83
|
+
#: models.py:13
|
|
84
|
+
msgid "Check it to grant access to this block to authenticated users only."
|
|
85
|
+
msgstr ""
|
|
86
|
+
|
|
87
|
+
#: models.py:14
|
|
88
|
+
msgid "Guests only"
|
|
89
|
+
msgstr ""
|
|
90
|
+
|
|
91
|
+
#: models.py:14
|
|
92
|
+
msgid "Check it to grant access to this block to guests only."
|
|
93
|
+
msgstr ""
|
|
94
|
+
|
|
95
|
+
#: models.py:15
|
|
96
|
+
msgid "Hidden"
|
|
97
|
+
msgstr "Caché"
|
|
98
|
+
|
|
99
|
+
#: models.py:15
|
|
100
|
+
msgid "Whether to show this block when requested."
|
|
101
|
+
msgstr "Inclure ou non ce contenu dans le gabarit."
|
|
102
|
+
|
|
103
|
+
#: models.py:18
|
|
104
|
+
msgid "Site Block"
|
|
105
|
+
msgstr "Site Block"
|
|
Binary file
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# SOME DESCRIPTIVE TITLE.
|
|
2
|
+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
3
|
+
# This file is distributed under the same license as the PACKAGE package.
|
|
4
|
+
#
|
|
5
|
+
# Translators:
|
|
6
|
+
# Igor Starikov <idlesign@yandex.ru>, 2013-2014
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: django-siteblocks\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: \n"
|
|
11
|
+
"POT-Creation-Date: 2014-09-21 12:39+0700\n"
|
|
12
|
+
"PO-Revision-Date: 2014-09-21 05:36+0000\n"
|
|
13
|
+
"Last-Translator: Igor Starikov <idlesign@yandex.ru>\n"
|
|
14
|
+
"Language-Team: Russian (http://www.transifex.com/projects/p/django-"
|
|
15
|
+
"siteblocks/language/ru/)\n"
|
|
16
|
+
"Language: ru\n"
|
|
17
|
+
"MIME-Version: 1.0\n"
|
|
18
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
|
19
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
20
|
+
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
|
21
|
+
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
|
22
|
+
|
|
23
|
+
#: admin.py:14
|
|
24
|
+
msgid "Basic settings"
|
|
25
|
+
msgstr "Основные настройки"
|
|
26
|
+
|
|
27
|
+
#: admin.py:17
|
|
28
|
+
msgid "Access settings"
|
|
29
|
+
msgstr "Настройки доступа"
|
|
30
|
+
|
|
31
|
+
#: admin.py:21
|
|
32
|
+
msgid "Additional settings"
|
|
33
|
+
msgstr "Дополнительные настройки"
|
|
34
|
+
|
|
35
|
+
#: config.py:9 models.py:19
|
|
36
|
+
msgid "Site Blocks"
|
|
37
|
+
msgstr "Блоки сайта"
|
|
38
|
+
|
|
39
|
+
#: models.py:9
|
|
40
|
+
msgid "Alias"
|
|
41
|
+
msgstr "Псевдоним"
|
|
42
|
+
|
|
43
|
+
#: models.py:9
|
|
44
|
+
msgid "Short name to address this block from a template."
|
|
45
|
+
msgstr "Краткое имя блока, для обращения к нему из шаблонов."
|
|
46
|
+
|
|
47
|
+
#: models.py:10
|
|
48
|
+
msgid "Description"
|
|
49
|
+
msgstr "Описание"
|
|
50
|
+
|
|
51
|
+
#: models.py:10
|
|
52
|
+
msgid "Short memo for this block."
|
|
53
|
+
msgstr "Произвольная заметка для блока."
|
|
54
|
+
|
|
55
|
+
#: models.py:11
|
|
56
|
+
msgid "URL"
|
|
57
|
+
msgstr "URL"
|
|
58
|
+
|
|
59
|
+
#: models.py:11
|
|
60
|
+
msgid ""
|
|
61
|
+
"Page URL this block is related to. Regular expressions supported (e.g.: \"/"
|
|
62
|
+
"news.*\" — everything under \"/news\").<br />View names are supported: "
|
|
63
|
+
"prepend <b>:</b> to view name <br /><b>Reserved URL alias:</b> \"*\" — "
|
|
64
|
+
"every page."
|
|
65
|
+
msgstr ""
|
|
66
|
+
"URL страницы, для которой актуален блок. Поддерживаются регулярные выражения "
|
|
67
|
+
"(например, \"/news.*\" — любые страницы ниже \"/news\").<br /"
|
|
68
|
+
">Поддерживаются обращения к представлениям: добавьте <b>:</b> перед именем "
|
|
69
|
+
"представления<br /><b>Зарезервированный псевдоним URL:</b> \"*\" — "
|
|
70
|
+
"любая страница."
|
|
71
|
+
|
|
72
|
+
#: models.py:12
|
|
73
|
+
msgid "Contents"
|
|
74
|
+
msgstr "Содержимое"
|
|
75
|
+
|
|
76
|
+
#: models.py:12
|
|
77
|
+
msgid "Block contents to render in a template."
|
|
78
|
+
msgstr "Содержимое блока для вывода на страницах."
|
|
79
|
+
|
|
80
|
+
#: models.py:13
|
|
81
|
+
msgid "Logged in only"
|
|
82
|
+
msgstr "Только авторизовавшиеся"
|
|
83
|
+
|
|
84
|
+
#: models.py:13
|
|
85
|
+
msgid "Check it to grant access to this block to authenticated users only."
|
|
86
|
+
msgstr ""
|
|
87
|
+
"Поставьте галочку, чтобы разрешить доступ к этому блоку только "
|
|
88
|
+
"авторизовавшимся."
|
|
89
|
+
|
|
90
|
+
#: models.py:14
|
|
91
|
+
msgid "Guests only"
|
|
92
|
+
msgstr "Только гости"
|
|
93
|
+
|
|
94
|
+
#: models.py:14
|
|
95
|
+
msgid "Check it to grant access to this block to guests only."
|
|
96
|
+
msgstr "Поставьте галочку, чтобы разрешить доступ к этому блоку только гостям."
|
|
97
|
+
|
|
98
|
+
#: models.py:15
|
|
99
|
+
msgid "Hidden"
|
|
100
|
+
msgstr "Скрыт"
|
|
101
|
+
|
|
102
|
+
#: models.py:15
|
|
103
|
+
msgid "Whether to show this block when requested."
|
|
104
|
+
msgstr "Определяет, можно ли выводить этот блок."
|
|
105
|
+
|
|
106
|
+
#: models.py:18
|
|
107
|
+
msgid "Site Block"
|
|
108
|
+
msgstr "Блок сайта"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import unicode_literals
|
|
3
|
+
|
|
4
|
+
from django.db import models, migrations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.CreateModel(
|
|
14
|
+
name='Block',
|
|
15
|
+
fields=[
|
|
16
|
+
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
|
17
|
+
('alias', models.CharField(help_text='Short name to address this block from a template.', max_length=80, verbose_name='Alias', db_index=True)),
|
|
18
|
+
('description', models.CharField(help_text='Short memo for this block.', max_length=100, null=True, verbose_name='Description', blank=True)),
|
|
19
|
+
('url', models.CharField(help_text='Page URL this block is related to. Regular expressions supported (e.g.: "/news.*" — everything under "/news").<br />View names are supported: prepend <b>:</b> to view name <br /><b>Reserved URL alias:</b> "*" — every page.', max_length=200, verbose_name='URL')),
|
|
20
|
+
('contents', models.TextField(help_text='Block contents to render in a template.', verbose_name='Contents')),
|
|
21
|
+
('hidden', models.BooleanField(default=False, help_text='Whether to show this block when requested.', db_index=True, verbose_name='Hidden')),
|
|
22
|
+
],
|
|
23
|
+
options={
|
|
24
|
+
'verbose_name': 'Site Block',
|
|
25
|
+
'verbose_name_plural': 'Site Blocks',
|
|
26
|
+
},
|
|
27
|
+
bases=(models.Model,),
|
|
28
|
+
),
|
|
29
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import unicode_literals
|
|
3
|
+
|
|
4
|
+
from django.db import models, migrations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('siteblocks', '0001_initial'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='block',
|
|
16
|
+
name='access_guest',
|
|
17
|
+
field=models.BooleanField(default=False, help_text='Check it to grant access to this item to guests only.', db_index=True, verbose_name='Guests only'),
|
|
18
|
+
preserve_default=True,
|
|
19
|
+
),
|
|
20
|
+
migrations.AddField(
|
|
21
|
+
model_name='block',
|
|
22
|
+
name='access_loggedin',
|
|
23
|
+
field=models.BooleanField(default=False, help_text='Check it to grant access to this item to authenticated users only.', db_index=True, verbose_name='Logged in only'),
|
|
24
|
+
preserve_default=True,
|
|
25
|
+
),
|
|
26
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 6.1.3 on 2026-11-09 14:56
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('siteblocks', '0002_auto_20140921_1038'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='block',
|
|
15
|
+
name='access_guest',
|
|
16
|
+
field=models.BooleanField(db_index=True, default=False, help_text='Check it to grant access to this block to guests only.', verbose_name='Guests only'),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='block',
|
|
20
|
+
name='access_loggedin',
|
|
21
|
+
field=models.BooleanField(db_index=True, default=False, help_text='Check it to grant access to this block to authenticated users only.', verbose_name='Logged in only'),
|
|
22
|
+
),
|
|
23
|
+
]
|
|
File without changes
|
siteblocks/models.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Block(models.Model):
|
|
6
|
+
|
|
7
|
+
alias = models.CharField(
|
|
8
|
+
_('Alias'), max_length=80, help_text=_('Short name to address this block from a template.'), db_index=True)
|
|
9
|
+
|
|
10
|
+
description = models.CharField(
|
|
11
|
+
_('Description'), max_length=100, help_text=_('Short memo for this block.'), null=True, blank=True)
|
|
12
|
+
|
|
13
|
+
url = models.CharField(
|
|
14
|
+
_('URL'), max_length=200,
|
|
15
|
+
help_text=_(
|
|
16
|
+
'Page URL this block is related to. Regular expressions supported (e.g.: "/news.*" — '
|
|
17
|
+
'everything under "/news").<br />'
|
|
18
|
+
'View names are supported: prepend <b>:</b> to view name <br />'
|
|
19
|
+
'<b>Reserved URL alias:</b> "*" — every page.'))
|
|
20
|
+
|
|
21
|
+
contents = models.TextField(
|
|
22
|
+
_('Contents'), help_text=_('Block contents to render in a template.'))
|
|
23
|
+
|
|
24
|
+
access_loggedin = models.BooleanField(
|
|
25
|
+
_('Logged in only'),
|
|
26
|
+
help_text=_('Check it to grant access to this block to authenticated users only.'),
|
|
27
|
+
db_index=True, default=False)
|
|
28
|
+
|
|
29
|
+
access_guest = models.BooleanField(
|
|
30
|
+
_('Guests only'),
|
|
31
|
+
help_text=_('Check it to grant access to this block to guests only.'), db_index=True, default=False)
|
|
32
|
+
|
|
33
|
+
hidden = models.BooleanField(
|
|
34
|
+
_('Hidden'), help_text=_('Whether to show this block when requested.'), db_index=True, default=False)
|
|
35
|
+
|
|
36
|
+
class Meta:
|
|
37
|
+
verbose_name = _('Site Block')
|
|
38
|
+
verbose_name_plural = _('Site Blocks')
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
return self.alias
|
siteblocks/settings.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from random import choice
|
|
4
|
+
from typing import Callable, Dict, List
|
|
5
|
+
|
|
6
|
+
from django.core.cache import cache
|
|
7
|
+
from django.db.models import signals
|
|
8
|
+
from django.template import Context
|
|
9
|
+
from django.urls import resolve, Resolver404
|
|
10
|
+
from django.utils.translation import get_language
|
|
11
|
+
|
|
12
|
+
from .models import Block
|
|
13
|
+
from .settings import I18N_SUPPORT
|
|
14
|
+
|
|
15
|
+
if I18N_SUPPORT:
|
|
16
|
+
|
|
17
|
+
def cache_get_key(block_alias: str) -> str:
|
|
18
|
+
return f'{block_alias}:{get_language()}'
|
|
19
|
+
|
|
20
|
+
else:
|
|
21
|
+
def cache_get_key(block_alias: str) -> str:
|
|
22
|
+
return block_alias
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Contains dynamic blocks.
|
|
26
|
+
_DYNAMIC_BLOCKS = defaultdict(list)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def register_dynamic_block(alias: str, callable: Callable):
|
|
30
|
+
"""Registers a callable that produces contents for a dynamic block.
|
|
31
|
+
|
|
32
|
+
Callable on call will get the following kwargs:
|
|
33
|
+
|
|
34
|
+
* `block_alias` - block alias,
|
|
35
|
+
* `block_context` - template context for block
|
|
36
|
+
|
|
37
|
+
Example::
|
|
38
|
+
|
|
39
|
+
# Put the following code somewhere where it'd be triggered as expected. E.g. in app view.py.
|
|
40
|
+
|
|
41
|
+
from random import choice
|
|
42
|
+
# Import the register function.
|
|
43
|
+
from siteblocks.siteblocksapp import register_dynamic_block
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# The following function will be used as a block contents producer.
|
|
47
|
+
def get_quote(**kwargs):
|
|
48
|
+
quotes = [ # From Terry Pratchett's Discworld novels.
|
|
49
|
+
'Ripples of paradox spread out across the sea of causality.',
|
|
50
|
+
'Early to rise, early to bed, makes a man healthy, wealthy and dead.',
|
|
51
|
+
'Granny had nothing against fortune-telling provided it was done badly by people with no talent for it.'
|
|
52
|
+
'Take it from me, there\'s nothing more terrible than someone out to do the world a favour.',
|
|
53
|
+
'The duke had a mind that ticked like a clock and, like a clock, it regularly went cuckoo.',
|
|
54
|
+
'Most gods find it hard to walk and think at the same time.',
|
|
55
|
+
'They didn\'t have to be funny - they were father jokes',
|
|
56
|
+
'Speak softly and employ a huge man with a crowbar.',
|
|
57
|
+
]
|
|
58
|
+
return choice(quotes)
|
|
59
|
+
|
|
60
|
+
# And we register our siteblock.
|
|
61
|
+
register_dynamic_block('quote', get_quote)
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
global _DYNAMIC_BLOCKS
|
|
65
|
+
_DYNAMIC_BLOCKS[alias].append(callable)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_dynamic_blocks() -> Dict[str, List[Callable]]:
|
|
69
|
+
"""Returns a dictionary with currently registered dynamic blocks."""
|
|
70
|
+
return _DYNAMIC_BLOCKS
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SiteBlocks:
|
|
74
|
+
|
|
75
|
+
# siteblocks objects are stored in Django cache for a year (60 * 60 * 24 * 365 = 31536000 sec).
|
|
76
|
+
# Cache is only invalidated on block item change.
|
|
77
|
+
CACHE_TIMEOUT: str = 31536000
|
|
78
|
+
CACHE_KEY: str = 'siteblocks'
|
|
79
|
+
|
|
80
|
+
IDX_GUEST: int = 0
|
|
81
|
+
IDX_AUTH: int = 1
|
|
82
|
+
|
|
83
|
+
def __init__(self):
|
|
84
|
+
self._cache = None
|
|
85
|
+
signals.post_save.connect(self._cache_empty, sender=Block)
|
|
86
|
+
signals.post_delete.connect(self._cache_empty, sender=Block)
|
|
87
|
+
|
|
88
|
+
def _cache_init(self):
|
|
89
|
+
"""Initializes local cache from Django cache."""
|
|
90
|
+
cache_ = cache.get(self.CACHE_KEY)
|
|
91
|
+
if cache_ is None:
|
|
92
|
+
cache_ = defaultdict(dict)
|
|
93
|
+
self._cache = cache_
|
|
94
|
+
|
|
95
|
+
def _cache_save(self):
|
|
96
|
+
cache.set(self.CACHE_KEY, self._cache, self.CACHE_TIMEOUT)
|
|
97
|
+
|
|
98
|
+
def _cache_get(self, key: str) -> List[Dict[str, List]]:
|
|
99
|
+
"""Returns cache entry parameter value by its name."""
|
|
100
|
+
return self._cache.get(key, False)
|
|
101
|
+
|
|
102
|
+
def _cache_set(self, key: str, value: List[Dict[str, List]]):
|
|
103
|
+
"""Replaces entire cache entry parameter data by its name with new data."""
|
|
104
|
+
self._cache[key] = value
|
|
105
|
+
|
|
106
|
+
def _cache_empty(self, **kwargs):
|
|
107
|
+
self._cache = None
|
|
108
|
+
cache.delete(self.CACHE_KEY)
|
|
109
|
+
|
|
110
|
+
def get_contents_static(self, block_alias: str, context: Context) -> str:
|
|
111
|
+
"""Returns contents of a static block."""
|
|
112
|
+
|
|
113
|
+
if 'request' not in context:
|
|
114
|
+
# No use in further actions as we won't ever know current URL.
|
|
115
|
+
return ''
|
|
116
|
+
|
|
117
|
+
current_url = context['request'].path
|
|
118
|
+
|
|
119
|
+
# Resolve current view name to support view names as block URLs.
|
|
120
|
+
try:
|
|
121
|
+
resolver_match = resolve(current_url)
|
|
122
|
+
namespace = ''
|
|
123
|
+
|
|
124
|
+
if resolver_match.namespaces:
|
|
125
|
+
# More than one namespace, really? Hmm.
|
|
126
|
+
namespace = resolver_match.namespaces[0]
|
|
127
|
+
|
|
128
|
+
resolved_view_name = f':{namespace}:{resolver_match.url_name}'
|
|
129
|
+
|
|
130
|
+
except Resolver404:
|
|
131
|
+
resolved_view_name = None
|
|
132
|
+
|
|
133
|
+
self._cache_init()
|
|
134
|
+
|
|
135
|
+
cache_entry_name = cache_get_key(block_alias)
|
|
136
|
+
idx_guest = self.IDX_GUEST
|
|
137
|
+
idx_auth = self.IDX_AUTH
|
|
138
|
+
|
|
139
|
+
siteblocks_static = self._cache_get(cache_entry_name)
|
|
140
|
+
|
|
141
|
+
if not siteblocks_static:
|
|
142
|
+
|
|
143
|
+
blocks = Block.objects.filter(
|
|
144
|
+
alias=block_alias,
|
|
145
|
+
hidden=False
|
|
146
|
+
).only('url', 'contents', 'access_guest', 'access_loggedin')
|
|
147
|
+
|
|
148
|
+
siteblocks_static = [defaultdict(list), defaultdict(list)]
|
|
149
|
+
|
|
150
|
+
for block in blocks:
|
|
151
|
+
|
|
152
|
+
if block.url == '*':
|
|
153
|
+
url_re = block.url
|
|
154
|
+
|
|
155
|
+
elif block.url.startswith(':'):
|
|
156
|
+
url_re = block.url
|
|
157
|
+
# Normalize URL name to include namespace.
|
|
158
|
+
if url_re.count(':') == 1:
|
|
159
|
+
url_re = f':{url_re}'
|
|
160
|
+
|
|
161
|
+
else:
|
|
162
|
+
url_re = re.compile(rf'{block.url}')
|
|
163
|
+
|
|
164
|
+
if block.access_guest:
|
|
165
|
+
siteblocks_static[idx_guest][url_re].append(block.contents)
|
|
166
|
+
|
|
167
|
+
elif block.access_loggedin:
|
|
168
|
+
siteblocks_static[idx_auth][url_re].append(block.contents)
|
|
169
|
+
|
|
170
|
+
else:
|
|
171
|
+
siteblocks_static[idx_guest][url_re].append(block.contents)
|
|
172
|
+
siteblocks_static[idx_auth][url_re].append(block.contents)
|
|
173
|
+
|
|
174
|
+
self._cache_set(cache_entry_name, siteblocks_static)
|
|
175
|
+
|
|
176
|
+
self._cache_save()
|
|
177
|
+
|
|
178
|
+
user = getattr(context['request'], 'user', None)
|
|
179
|
+
is_authenticated = getattr(user, 'is_authenticated', False)
|
|
180
|
+
|
|
181
|
+
lookup_area = siteblocks_static[idx_auth if is_authenticated else idx_guest]
|
|
182
|
+
|
|
183
|
+
static_block_contents = ''
|
|
184
|
+
|
|
185
|
+
if '*' in lookup_area:
|
|
186
|
+
static_block_contents = choice(lookup_area['*'])
|
|
187
|
+
|
|
188
|
+
elif resolved_view_name in lookup_area:
|
|
189
|
+
static_block_contents = choice(lookup_area[resolved_view_name])
|
|
190
|
+
|
|
191
|
+
else:
|
|
192
|
+
for url, contents in lookup_area.items():
|
|
193
|
+
if url.match(current_url):
|
|
194
|
+
static_block_contents = choice(contents)
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
return static_block_contents
|
|
198
|
+
|
|
199
|
+
def get_contents_dynamic(self, block_alias: str, context: Context) -> str:
|
|
200
|
+
"""Returns contents of a dynamic block."""
|
|
201
|
+
dynamic_block = get_dynamic_blocks().get(block_alias, [])
|
|
202
|
+
|
|
203
|
+
if not dynamic_block:
|
|
204
|
+
return ''
|
|
205
|
+
|
|
206
|
+
dynamic_block = choice(dynamic_block)
|
|
207
|
+
return dynamic_block(block_alias=block_alias, block_context=context)
|
|
208
|
+
|
|
209
|
+
def get(self, block_alias: str, context: Context) -> str:
|
|
210
|
+
"""Main method returning block contents (static or dynamic)."""
|
|
211
|
+
contents = []
|
|
212
|
+
|
|
213
|
+
dynamic_block_contents = self.get_contents_dynamic(block_alias, context)
|
|
214
|
+
if dynamic_block_contents:
|
|
215
|
+
contents.append(dynamic_block_contents)
|
|
216
|
+
|
|
217
|
+
static_block_contents = self.get_contents_static(block_alias, context)
|
|
218
|
+
if static_block_contents:
|
|
219
|
+
contents.append(static_block_contents)
|
|
220
|
+
|
|
221
|
+
if not contents:
|
|
222
|
+
return ''
|
|
223
|
+
|
|
224
|
+
return choice(contents)
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from django import template
|
|
2
|
+
from django.template.base import FilterExpression, Parser, Token
|
|
3
|
+
|
|
4
|
+
from ..siteblocksapp import SiteBlocks
|
|
5
|
+
|
|
6
|
+
register = template.Library()
|
|
7
|
+
|
|
8
|
+
# Utility methods are implemented in SiteBlocks class
|
|
9
|
+
siteblocks = SiteBlocks()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@register.tag
|
|
13
|
+
def siteblock(parser: Parser, token: Token):
|
|
14
|
+
"""Two notation types are acceptable:
|
|
15
|
+
|
|
16
|
+
1. Two arguments:
|
|
17
|
+
{% siteblock "myblock" %}
|
|
18
|
+
Used to render "myblock" site block.
|
|
19
|
+
|
|
20
|
+
2. Four arguments:
|
|
21
|
+
{% siteblock "myblock" as myvar %}
|
|
22
|
+
Used to put "myblock" site block into "myvar" template variable.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
tokens = token.split_contents()
|
|
26
|
+
tokens_num = len(tokens)
|
|
27
|
+
|
|
28
|
+
if tokens_num not in (2, 4):
|
|
29
|
+
raise template.TemplateSyntaxError(
|
|
30
|
+
f'{tokens[0]} tag requires two or four arguments. '
|
|
31
|
+
'E.g.: {%% siteblock "myblock" %%} or {%% siteblock "myblock" as myvar %%}.')
|
|
32
|
+
|
|
33
|
+
block_alias = parser.compile_filter(tokens[1])
|
|
34
|
+
as_var = None
|
|
35
|
+
tokens = tokens[2:]
|
|
36
|
+
|
|
37
|
+
if len(tokens) >= 2 and tokens[-2] == 'as':
|
|
38
|
+
as_var = tokens[-1]
|
|
39
|
+
|
|
40
|
+
return siteblockNode(block_alias, as_var)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class siteblockNode(template.Node):
|
|
44
|
+
|
|
45
|
+
def __init__(self, block_alias, as_var=None):
|
|
46
|
+
self.block_alias = block_alias
|
|
47
|
+
self.as_var = as_var
|
|
48
|
+
|
|
49
|
+
def render(self, context):
|
|
50
|
+
block_alias = self.block_alias
|
|
51
|
+
if isinstance(self.block_alias, FilterExpression):
|
|
52
|
+
block_alias = block_alias.resolve(context)
|
|
53
|
+
|
|
54
|
+
contents = siteblocks.get(block_alias, context)
|
|
55
|
+
|
|
56
|
+
if self.as_var is not None:
|
|
57
|
+
context[self.as_var] = contents
|
|
58
|
+
return ''
|
|
59
|
+
|
|
60
|
+
return contents
|