4 |
5 | {{ object.text|safe }}
6 |
7 | {% if admin_url %}edit{% endif %}
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/de/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/locale/de/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/de/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
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 , 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: 2009-09-08 10:29+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | #: admin.py:22
20 | msgid "change related object"
21 | msgstr "Verknüpftes Objekt ändern"
22 |
23 | #: models.py:8
24 | msgid "slug"
25 | msgstr "Slug"
26 |
27 | #: contrib/gblocks/models.py:5 contrib/gblocks/models.py:23
28 | #: contrib/gblocks/models.py:30
29 | msgid "title"
30 | msgstr "Title"
31 |
32 | #: contrib/gblocks/models.py:11 contrib/gblocks/models.py:24
33 | #: contrib/gblocks/models.py:31
34 | msgid "text"
35 | msgstr "Text"
36 |
37 | #: contrib/gblocks/models.py:17 contrib/gblocks/models.py:32
38 | msgid "image"
39 | msgstr "Bild"
40 |
41 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:6
42 | msgid "Notice"
43 | msgstr "Hinweis"
44 |
45 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:7
46 | #, python-format
47 | msgid ""
48 | "This object stores only the path to the related %(related_app_label)s/%"
49 | "(related_model_name)s object with the primary key %(related_pk)s"
50 | "em>."
51 | msgstr ""
52 | "Dieses Objekt enthält nur den Pfad zum verknüpften %(related_app_label)s/"
53 | "%(related_model_name)s Objekt mit dem Primärschlüssel %(related_pk)"
54 | "s."
55 |
56 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:9
57 | msgid "Click this link to edit the object itself."
58 | msgstr "Klicken Sie diesen Link um das Objekt selbst zu bearbeiten."
59 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/dk/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/locale/dk/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/dk/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # django-generic-flatblocks in Danish.
2 | # django-generic-flatblocks på Dansk.
3 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
4 | # This file is distributed under the same license as the PACKAGE package.
5 | # Michael Lind Mortensen , 2009.
6 | #
7 | #, fuzzy
8 | msgid ""
9 | msgstr ""
10 | "Project-Id-Version: PACKAGE VERSION\n"
11 | "Report-Msgid-Bugs-To: \n"
12 | "POT-Creation-Date: 2009-09-04 12:10+0200\n"
13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14 | "Last-Translator: FULL NAME \n"
15 | "Language-Team: 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:22
21 | msgid "change related object"
22 | msgstr "ændre relateret objekt"
23 |
24 | #: models.py:8
25 | msgid "slug"
26 | msgstr "slug"
27 |
28 | #: contrib/gblocks/models.py:5 contrib/gblocks/models.py:23
29 | #: contrib/gblocks/models.py:30
30 | msgid "title"
31 | msgstr "titel"
32 |
33 | #: contrib/gblocks/models.py:11 contrib/gblocks/models.py:24
34 | #: contrib/gblocks/models.py:31
35 | msgid "text"
36 | msgstr "tekst"
37 |
38 | #: contrib/gblocks/models.py:17 contrib/gblocks/models.py:32
39 | msgid "image"
40 | msgstr "billede"
41 |
42 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:6
43 | msgid "Notice"
44 | msgstr "Notifikation"
45 |
46 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:7
47 | #, python-format
48 | msgid ""
49 | "This object stores only the path to the related %(related_app_label)s/%"
50 | "(related_model_name)s object with the primary key %(related_pk)s"
51 | "em>."
52 | msgstr ""
53 | "Dette objekt gemmer udelukkende stien til det relaterede %(related_app_label)s/%"
54 | "(related_model_name)s objekt med den primære nøgle %(related_pk)s"
55 | "em>."
56 |
57 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:9
58 | msgid "Click this link to edit the object itself."
59 | msgstr "Klik på dette link for at ændre objektet selv."
60 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/en/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/locale/en/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/en/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
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 , 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: 2009-09-08 10:29+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | #: admin.py:22
20 | msgid "change related object"
21 | msgstr ""
22 |
23 | #: models.py:8
24 | msgid "slug"
25 | msgstr ""
26 |
27 | #: contrib/gblocks/models.py:5 contrib/gblocks/models.py:23
28 | #: contrib/gblocks/models.py:30
29 | msgid "title"
30 | msgstr ""
31 |
32 | #: contrib/gblocks/models.py:11 contrib/gblocks/models.py:24
33 | #: contrib/gblocks/models.py:31
34 | msgid "text"
35 | msgstr ""
36 |
37 | #: contrib/gblocks/models.py:17 contrib/gblocks/models.py:32
38 | msgid "image"
39 | msgstr ""
40 |
41 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:6
42 | msgid "Notice"
43 | msgstr ""
44 |
45 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:7
46 | #, python-format
47 | msgid ""
48 | "This object stores only the path to the related %(related_app_label)s/%"
49 | "(related_model_name)s object with the primary key %(related_pk)s"
50 | "em>."
51 | msgstr ""
52 |
53 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:9
54 | msgid "Click this link to edit the object itself."
55 | msgstr ""
56 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/fr/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/locale/fr/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/django_generic_flatblocks/locale/fr/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
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 , 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: 2011-08-27 23:52-0400\n"
12 | "PO-Revision-Date: 2011-08-27 11:57+EDT\n"
13 | "Last-Translator: Maxime Haineault \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: French\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "Plural-Forms: nplurals=2; plural=(n > 1)\n"
20 |
21 | #: admin.py:22
22 | msgid "change related object"
23 | msgstr "Modifier l'objet relié"
24 |
25 | #: models.py:7
26 | msgid "slug"
27 | msgstr "slug"
28 |
29 | #: contrib/gblocks/models.py:5 contrib/gblocks/models.py:23
30 | #: contrib/gblocks/models.py:30
31 | msgid "title"
32 | msgstr "titre"
33 |
34 | #: contrib/gblocks/models.py:11 contrib/gblocks/models.py:24
35 | #: contrib/gblocks/models.py:31
36 | msgid "text"
37 | msgstr "text"
38 |
39 | #: contrib/gblocks/models.py:17 contrib/gblocks/models.py:32
40 | msgid "image"
41 | msgstr "image"
42 |
43 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:6
44 | msgid "Notice"
45 | msgstr "Note"
46 |
47 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:7
48 | #, python-format
49 | msgid ""
50 | "This object stores only the path to the related %(related_app_label)s/"
51 | "%(related_model_name)s object with the primary key %(related_pk)s"
52 | "em>."
53 | msgstr ""
54 | "Cet objet ne sert que de liaison vers l'objet %(related_app_label)s/"
55 | "%(related_model_name)s avec la clé primaire %(related_pk)s"
56 | "em>."
57 |
58 |
59 | #: templates/admin/django_generic_flatblocks/change_form_forward.html:9
60 | msgid "Click this link to edit the object itself."
61 | msgstr "Cliquer ce lien pour modifier l'objet désigné."
62 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9 on 2016-03-23 12:03
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | initial = True
12 |
13 | dependencies = [
14 | ('contenttypes', '0002_remove_content_type_name'),
15 | ]
16 |
17 | operations = [
18 | migrations.CreateModel(
19 | name='GenericFlatblock',
20 | fields=[
21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22 | ('slug', models.SlugField(max_length=255, unique=True, verbose_name='slug')),
23 | ('object_id', models.PositiveIntegerField()),
24 | ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
25 | ],
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/migrations/__init__.py
--------------------------------------------------------------------------------
/django_generic_flatblocks/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.contenttypes.fields import GenericForeignKey
2 | from django.contrib.contenttypes.models import ContentType
3 | from django.db import models
4 | from django.utils.encoding import python_2_unicode_compatible
5 | from django.utils.translation import ugettext_lazy as _
6 |
7 |
8 | @python_2_unicode_compatible
9 | class GenericFlatblock(models.Model):
10 | slug = models.SlugField(_('slug'), max_length=255, unique=True)
11 | content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
12 | object_id = models.PositiveIntegerField()
13 | content_object = GenericForeignKey('content_type', 'object_id')
14 |
15 | def __str__(self):
16 | return self.slug
17 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/templates/admin/django_generic_flatblocks/change_form_forward.html:
--------------------------------------------------------------------------------
1 | {% extends "admin/change_form.html" %}
2 | {% load i18n %}
3 |
4 | {% block content %}
5 |
6 | {% trans "Notice" %}:
7 | {% blocktrans with related_object.pk as related_pk %}This object stores only the path to the related {{related_app_label}}/{{related_model_name}} object with the primary key {{ related_pk }}.{% endblocktrans %}
8 |
{% trans "Click this link to edit the object itself." %}
10 | {{ block.super }}
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/templatetags/__init__.py
--------------------------------------------------------------------------------
/django_generic_flatblocks/templatetags/generic_flatblocks.py:
--------------------------------------------------------------------------------
1 | from django import VERSION
2 | from django.apps import apps
3 | from django.conf import settings
4 | from django.template import (
5 | Library,
6 | Node,
7 | Variable,
8 | )
9 | from django.template.defaultfilters import slugify
10 | from django.template.loader import select_template
11 |
12 | from django_generic_flatblocks.models import GenericFlatblock
13 |
14 | from logging import getLogger
15 |
16 | logger = getLogger(__file__)
17 | register = Library()
18 | DJANGO_20 = VERSION[0] >= 2
19 |
20 |
21 | class GenericFlatblockNode(Node):
22 | def __init__(
23 | self,
24 | slug,
25 | modelname=None,
26 | template_path=None,
27 | variable_name=None,
28 | store_in_object=None,
29 | ):
30 | self.slug = slug
31 | self.modelname = modelname
32 | self.template_path = template_path
33 | self.variable_name = variable_name
34 | self.store_in_object = store_in_object
35 |
36 | def generate_slug(self, slug, context):
37 | """
38 | Generates a slug out of a comma-separated string. Automatically resolves
39 | variables in it. Examples::
40 |
41 | "website","title" -> website_title
42 | "website",LANGUAGE_CODE -> website_en
43 | """
44 | # If the user passed a integer as slug, use it as a primary key in
45 | # self.get_content_object()
46 | if not ',' in slug and isinstance(self.resolve(slug, context), int):
47 | return self.resolve(slug, context)
48 | return slugify(
49 | '_'.join([str(self.resolve(i, context)) for i in slug.split(',')])
50 | )
51 |
52 | def generate_admin_link(self, related_object, context):
53 | """
54 | Generates a link to contrib.admin change view. In Django 1.1 this
55 | will work automatically using urlresolvers.
56 | """
57 | app_label = related_object._meta.app_label
58 | model_name = related_object._meta.model_name
59 |
60 | # Check if user has change permissions
61 | if DJANGO_20:
62 | # Django 1.10+ made is_authenticated a property, 2.0 removed
63 | # the fallback.
64 | authenticated = context['request'].user.is_authenticated
65 | else:
66 | authenticated = context['request'].user.is_authenticated()
67 | if authenticated and context['request'].user.has_perm(
68 | '%s.change' % model_name
69 | ):
70 | admin_url_prefix = getattr(settings, 'ADMIN_URL_PREFIX', '/admin/')
71 | return '%s%s/%s/%s/' % (
72 | admin_url_prefix,
73 | app_label,
74 | model_name,
75 | related_object.pk,
76 | )
77 | else:
78 | return None
79 |
80 | def get_content_object(self, related_model, slug):
81 |
82 | # If the user passed a Integer as a slug, assume that we should fetch
83 | # this specific object
84 | if isinstance(slug, int):
85 | try:
86 | related_object = related_model._default_manager.get(pk=slug)
87 | return None, related_object
88 | except related_model.DoesNotExist:
89 | if settings.DEBUG:
90 | raise
91 | related_object = related_model()
92 | return None, related_object
93 |
94 | # Otherwise, try to generate a new, related object
95 | try:
96 | generic_object = GenericFlatblock._default_manager.get(slug=slug)
97 | related_object = generic_object.content_object
98 | if related_object is None:
99 | # The related object must have been deleted. Let's start over.
100 | generic_object.delete()
101 | raise GenericFlatblock.DoesNotExist
102 | except GenericFlatblock.DoesNotExist:
103 | related_object = related_model._default_manager.create()
104 | generic_object = GenericFlatblock._default_manager.create(
105 | slug=slug, content_object=related_object
106 | )
107 | return generic_object, related_object
108 |
109 | def resolve(self, var, context):
110 | """Resolves a variable out of context if it's not in quotes"""
111 | if var[0] in ('"', "'") and var[-1] == var[0]:
112 | return var[1:-1]
113 | else:
114 | return Variable(var).resolve(context)
115 |
116 | def resolve_model_for_label(self, modelname, context):
117 | """resolves a model for a applabel.modelname string"""
118 | applabel, modellabel = self.resolve(modelname, context).split(".")
119 | related_model = apps.get_model(applabel, modellabel)
120 | return related_model
121 |
122 | def render(self, context):
123 |
124 | slug = self.generate_slug(self.slug, context)
125 | related_model = self.resolve_model_for_label(self.modelname, context)
126 |
127 | # Get the generic and related object
128 | generic_object, related_object = self.get_content_object(
129 | related_model, slug
130 | )
131 | admin_url = self.generate_admin_link(related_object, context)
132 |
133 | # if "into" is provided, store the related object into this variable
134 | if self.store_in_object:
135 | into_var = self.resolve(self.store_in_object, context)
136 | context[into_var] = related_object
137 | context["%s_generic_object" % into_var] = generic_object
138 | context["%s_admin_url" % into_var] = admin_url
139 | return ''
140 |
141 | # Add the model instances to the current context
142 | context['generic_object'] = generic_object
143 | context['object'] = related_object
144 | context['admin_url'] = admin_url
145 |
146 | # Resolve the template(s)
147 | template_paths = []
148 | if self.template_path:
149 | template_paths.append(self.resolve(self.template_path, context))
150 | template_paths.append(
151 | '%s/%s/flatblock.html'
152 | % tuple(self.resolve(self.modelname, context).lower().split("."))
153 | )
154 |
155 | try:
156 | t = select_template(template_paths)
157 | except Exception as e:
158 | logger.exception(e)
159 | if settings.DEBUG:
160 | raise e
161 | return ''
162 |
163 | content = t.template.render(context)
164 |
165 | # Set content as variable inside context, if variable_name is given
166 | if self.variable_name:
167 | context[self.resolve(self.variable_name, context)] = content
168 | return ''
169 | return content
170 |
171 |
172 | def do_genericflatblock(parser, token):
173 | """
174 | {% gblock "slug" for "appname.modelname" %}
175 | {% gblock "slug" for "appname.modelname" into "slug_object" %}
176 | {% gblock "slug" for "appname.modelname" with "templatename.html" %}
177 | {% gblock "slug" for "appname.modelname" with "templatename.html" as "variable" %}
178 | """
179 |
180 | def next_bit_for(bits, key, if_none=None):
181 | try:
182 | return bits[bits.index(key) + 1]
183 | except ValueError:
184 | return if_none
185 |
186 | bits = token.contents.split()
187 | args = {
188 | 'slug': next_bit_for(bits, 'gblock'),
189 | 'modelname': next_bit_for(bits, 'for'),
190 | 'template_path': next_bit_for(bits, 'with'),
191 | 'variable_name': next_bit_for(bits, 'as'),
192 | 'store_in_object': next_bit_for(bits, 'into'),
193 | }
194 | return GenericFlatblockNode(**args)
195 |
196 |
197 | register.tag('gblock', do_genericflatblock)
198 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/tests/__init__.py
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/templates/auth/user/flatblock.html:
--------------------------------------------------------------------------------
1 | {{ object.username }}
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/templates/auth/user/flatblock_firstname.html:
--------------------------------------------------------------------------------
1 | {{ object.first_name }}
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/templates/test_template.html:
--------------------------------------------------------------------------------
1 | {{ object.title }}
2 | {{ admin_url }}
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/test_flatblocks.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.template import Template, TemplateDoesNotExist, TemplateSyntaxError
3 | from django.template.context import Context
4 | from django.test import TestCase
5 |
6 |
7 | class HttpRequest(object):
8 | """
9 | Stupid simple HttpRequest class to store a user. May need to be expanded
10 | in the future to act more like the real deal.
11 | """
12 |
13 | def __init__(self, user):
14 | self.user = user
15 |
16 |
17 | class GenericFlatblocksTestCase(TestCase):
18 | def setUp(self):
19 | # Create a dummy user
20 | from django.contrib.auth.models import User
21 |
22 | dummy_user = User.objects.create_user(
23 | u'johndoe', u'john@example.com', u'foobar'
24 | )
25 | dummy_user.first_name = u'John'
26 | dummy_user.last_naem = u'Doe'
27 | dummy_user.save()
28 |
29 | self.assertEqual(dummy_user.pk, 1)
30 | self.dummy_user = dummy_user
31 |
32 | self.admin_user = User.objects.create_superuser(
33 | u'admin', u'admin@example.com', u'foobar'
34 | )
35 |
36 | def tearDown(self):
37 | from django.contrib.auth.models import User
38 |
39 | User.objects.all().delete()
40 |
41 | def parseTemplate(self, template_string, admin_user=False):
42 | user = admin_user and self.admin_user or self.dummy_user
43 | t = Template(template_string)
44 | c = Context(
45 | {'user': user, 'request': HttpRequest(user), 'LANGUAGE_CODE': 'en'}
46 | )
47 | return t.render(c)
48 |
49 | def testModelBehaviour(self):
50 | """
51 | Direct flatblock creation.
52 | """
53 | from django_generic_flatblocks.models import GenericFlatblock
54 | from django_generic_flatblocks.contrib.gblocks.models import Title
55 |
56 | title_obj = Title.objects.create(title=u'Hello World')
57 | generic_obj = GenericFlatblock()
58 | generic_obj.slug = u'hello_world'
59 | generic_obj.content_object = title_obj
60 | generic_obj.save()
61 |
62 | self.assertEqual(generic_obj.slug, u'hello_world')
63 | self.assertEqual(generic_obj.content_object, title_obj)
64 | self.assertEqual(generic_obj.__str__(), u'hello_world')
65 |
66 | def testSlugArgument(self):
67 | from django_generic_flatblocks.models import GenericFlatblock
68 |
69 | template_string = '''
70 | {% load generic_flatblocks %}
71 | {% gblock "title" for "gblocks.Title" %}
72 | {% gblock "title","foo" for "gblocks.Title" %}
73 | {% gblock "title","foo",LANGUAGE_CODE for "gblocks.Title" %}
74 | {% gblock "user",user.pk for "gblocks.Title" %}
75 | {% gblock "int","slug",1 for "gblocks.Title" %}
76 | '''
77 | self.parseTemplate(template_string)
78 | self.assertTrue(GenericFlatblock.objects.get(slug='title'))
79 | self.assertTrue(GenericFlatblock.objects.get(slug='title_foo'))
80 | self.assertTrue(GenericFlatblock.objects.get(slug='title_foo_en'))
81 | self.assertTrue(GenericFlatblock.objects.get(slug='user_1'))
82 | self.assertTrue(GenericFlatblock.objects.get(slug='int_slug_1'))
83 |
84 | def testSlugArgumentWithInteger(self):
85 | # Integer slug
86 | template_string = '''
87 | {% load generic_flatblocks %}
88 | {% gblock 1 for "auth.user" %}
89 | '''
90 | t = self.parseTemplate(template_string)
91 | self.assertTrue(self.dummy_user.username in t)
92 |
93 | # Integer slug with custom template
94 | template_string = '''
95 | {% load generic_flatblocks %}
96 | {% gblock 1 for "auth.user" with "auth/user/flatblock_firstname.html" %}
97 | '''
98 | t = self.parseTemplate(template_string)
99 | self.assertTrue(self.dummy_user.first_name in t)
100 |
101 | # Non exisiting integer, empty template
102 | template_string = '''
103 | {% load generic_flatblocks %}
104 | {% gblock 5 for "auth.user" %}
105 | '''
106 | t = self.parseTemplate(template_string)
107 | self.assertFalse(t.strip())
108 |
109 | def testForArgument(self):
110 | template_string = '''
111 | {% load generic_flatblocks %}
112 | {% gblock "title" for "foo.Bar" %}
113 | '''
114 | self.assertRaises(LookupError, self.parseTemplate, template_string)
115 |
116 | # Missing for argument
117 | template_string = '''
118 | {% load generic_flatblocks %}
119 | {% gblock "title" %}
120 | '''
121 | self.assertRaises(TypeError, self.parseTemplate, template_string)
122 |
123 | def testWithArgument(self):
124 | # With template string
125 | template_string = '''
126 | {% load generic_flatblocks %}
127 | {% gblock "title" for "gblocks.Title" with "test_template.html" %}
128 | '''
129 | t = self.parseTemplate(template_string)
130 | self.assertTrue(u'' in t)
131 |
132 | # Non existing templates should fallback to the default one
133 | template_string = '''
134 | {% load generic_flatblocks %}
135 | {% gblock "title" for "gblocks.Title" with "test_template_doesnotexist.html" %}
136 | '''
137 | t = self.parseTemplate(template_string)
138 | self.assertTrue(u'
' in t)
139 |
140 | # Raise exception if the template does not exist if DEBUG is True
141 | settings.DEBUG = True
142 | template_string = '''
143 | {% load generic_flatblocks %}
144 | {% gblock "title" for "auth.Permission" %}
145 | '''
146 | self.assertRaises(
147 | (TemplateDoesNotExist, TemplateSyntaxError),
148 | self.parseTemplate,
149 | template_string,
150 | )
151 | settings.DEBUG = False
152 |
153 | # Fail silently if the template does not exist but DEBUG is False
154 | template_string = '''
155 | {% load generic_flatblocks %}
156 | {% gblock "title" for "auth.Permission" %}
157 | '''
158 | self.assertTrue(self.parseTemplate(template_string).strip() == u'')
159 |
160 | def testAsArgument(self):
161 | template_string = '''
162 | {% load generic_flatblocks %}
163 | {% gblock "title" for "gblocks.Title" as "title_object" %}
164 |
{{ title_object }}
165 | '''
166 | t = self.parseTemplate(template_string)
167 | t = ''.join(t.splitlines()) # Remove spaces
168 | self.assertTrue(u'
' in t)
169 |
170 | def testIntoArgument(self):
171 | template_string = '''
172 | {% load generic_flatblocks %}
173 | {% gblock "title" for "gblocks.Title" into "title_object" %}
174 | {{ title_object.title }}
175 | '''
176 | self.parseTemplate(template_string)
177 |
178 | from django_generic_flatblocks.models import GenericFlatblock
179 |
180 | o = GenericFlatblock.objects.get(slug='title')
181 | o.content_object.title = u'Into Argument'
182 | o.content_object.save()
183 |
184 | t = self.parseTemplate(template_string)
185 | self.assertTrue(u'Into Argument' in t)
186 |
187 | template_string = '''
188 | {% load generic_flatblocks %}
189 | {% gblock 1 for "auth.User" into "the_user" %}
190 | {{ the_user.username }}
191 | '''
192 | t = self.parseTemplate(template_string)
193 | self.assertTrue(u'johndoe' in t)
194 |
195 | template_string = '''
196 | {% load generic_flatblocks %}
197 | {% gblock 5 for "auth.User" into "the_user" %}
198 | {{ the_user.username }}
199 | '''
200 | t = self.parseTemplate(template_string)
201 | self.assertTrue(u'' in t)
202 |
203 | from django.contrib.auth.models import User
204 |
205 | settings.DEBUG = True
206 | template_string = '''
207 | {% load generic_flatblocks %}
208 | {% gblock 5 for "auth.User" into "the_user" %}
209 | {{ the_user.username }}
210 | '''
211 | self.assertRaises(
212 | (User.DoesNotExist, TemplateSyntaxError),
213 | self.parseTemplate,
214 | template_string,
215 | )
216 | settings.DEBUG = False
217 |
218 | def testRelatedObjectDeletion(self):
219 | template_string = '''
220 | {% load generic_flatblocks %}
221 | {% gblock "title" for "gblocks.Title" into "title_object" %}
222 | {{ title_object.title }}
223 | '''
224 | self.parseTemplate(template_string)
225 |
226 | from django_generic_flatblocks.models import GenericFlatblock
227 |
228 | o = GenericFlatblock.objects.get(slug='title')
229 | old_content_object = o.content_object
230 | o.content_object.delete()
231 |
232 | template_string = '''
233 | {% load generic_flatblocks %}
234 | {% gblock "title" for "gblocks.Title" into "title_object" %}
235 | {{ title_object.title }}
236 | '''
237 | self.parseTemplate(template_string)
238 | o = GenericFlatblock.objects.get(slug='title')
239 | self.assertNotEqual(old_content_object, o.content_object)
240 |
241 | def testContributedModels(self):
242 |
243 | template_string = '''
244 | {% load generic_flatblocks %}
245 | {% gblock "title" for "gblocks.Title" %}
246 | {% gblock "text" for "gblocks.Text" %}
247 | {% gblock "image" for "gblocks.Image" %}
248 | {% gblock "title_and_text" for "gblocks.TitleAndText" %}
249 | {% gblock "title_text_and_image" for "gblocks.TitleTextAndImage" %}
250 | '''
251 | self.parseTemplate(template_string)
252 |
253 | from django_generic_flatblocks.contrib.gblocks import models
254 | from django_generic_flatblocks.models import GenericFlatblock
255 |
256 | self.assertTrue(
257 | isinstance(
258 | GenericFlatblock.objects.get(slug=u'title').content_object,
259 | models.Title,
260 | )
261 | )
262 | self.assertTrue(
263 | isinstance(
264 | GenericFlatblock.objects.get(slug=u'text').content_object,
265 | models.Text,
266 | )
267 | )
268 | self.assertTrue(
269 | isinstance(
270 | GenericFlatblock.objects.get(slug=u'image').content_object,
271 | models.Image,
272 | )
273 | )
274 | self.assertTrue(
275 | isinstance(
276 | GenericFlatblock.objects.get(
277 | slug=u'title_and_text'
278 | ).content_object,
279 | models.TitleAndText,
280 | )
281 | )
282 | self.assertTrue(
283 | isinstance(
284 | GenericFlatblock.objects.get(
285 | slug=u'title_text_and_image'
286 | ).content_object,
287 | models.TitleTextAndImage,
288 | )
289 | )
290 |
291 | # Test str method of contributed models
292 | self.assertTrue(
293 | GenericFlatblock.objects.get(slug=u'title').content_object.__str__()
294 | )
295 | self.assertTrue(
296 | GenericFlatblock.objects.get(slug=u'text').content_object.__str__()
297 | )
298 | self.assertTrue(
299 | GenericFlatblock.objects.get(slug=u'image').content_object.__str__()
300 | )
301 | self.assertTrue(
302 | GenericFlatblock.objects.get(
303 | slug=u'title_and_text'
304 | ).content_object.__str__()
305 | )
306 | self.assertTrue(
307 | GenericFlatblock.objects.get(
308 | slug=u'title_text_and_image'
309 | ).content_object.__str__()
310 | )
311 |
312 | def testAdminLink(self):
313 | template_string = '''
314 | {% load generic_flatblocks %}
315 | {% gblock "title" for "gblocks.Title" with "test_template.html" %}
316 | '''
317 | t = self.parseTemplate(template_string, admin_user=True)
318 | self.assertTrue("/admin/gblocks/title/1/" in t)
319 |
320 | # The admin link gets appended to the "into" argument
321 | template_string = '''
322 | {% load generic_flatblocks %}
323 | {% gblock "title" for "gblocks.Title" into "title_object" %}
324 | {{ title_object_admin_url }}
325 | '''
326 | t = self.parseTemplate(template_string, admin_user=True)
327 | self.assertTrue("/admin/gblocks/title/1/" in t)
328 |
329 | # You can define the admin prefix using a setting
330 | from django.conf import settings
331 |
332 | settings.ADMIN_URL_PREFIX = '/secret-admin-url/'
333 |
334 | template_string = '''
335 | {% load generic_flatblocks %}
336 | {% gblock "title" for "gblocks.Title" with "test_template.html" %}
337 | '''
338 | t = self.parseTemplate(template_string, admin_user=True)
339 | self.assertTrue("/secret-admin-url/gblocks/title/1/" in t)
340 |
341 | template_string = '''
342 | {% load generic_flatblocks %}
343 | {% gblock "title" for "gblocks.Title" into "title_object" %}
344 | {{ title_object_admin_url }}
345 | '''
346 | t = self.parseTemplate(template_string, admin_user=True)
347 | self.assertTrue("/secret-admin-url/gblocks/title/1/" in t)
348 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/testapp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bartTC/django-generic-flatblocks/a5df4f12dcbcd6c4e34d4bb3b777c7702baaf6bc/django_generic_flatblocks/tests/testapp/__init__.py
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/testapp/settings.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | DEBUG = True
4 |
5 | TESTAPP_DIR = os.path.abspath(os.path.dirname(__file__))
6 |
7 | SECRET_KEY = 'testsecretkey'
8 |
9 | ALLOWED_HOSTS = ['*']
10 |
11 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
12 |
13 | DATABASES = {
14 | 'default': {
15 | 'ENGINE': 'django.db.backends.sqlite3',
16 | 'NAME': os.path.join(TESTAPP_DIR, 'testdb.sqlite'),
17 | }
18 | }
19 |
20 | STATIC_ROOT = os.path.join(TESTAPP_DIR, '.static')
21 | MEDIA_ROOT = os.path.join(TESTAPP_DIR, '.uploads')
22 |
23 | STATIC_URL = '/static/'
24 | MEDIA_URL = '/uploads/'
25 |
26 | ROOT_URLCONF = 'django_generic_flatblocks.tests.testapp.urls'
27 |
28 | INSTALLED_APPS = [
29 | 'django_generic_flatblocks',
30 | 'django_generic_flatblocks.tests',
31 | 'django_generic_flatblocks.contrib.gblocks',
32 | 'django.contrib.admin',
33 | 'django.contrib.auth',
34 | 'django.contrib.contenttypes',
35 | 'django.contrib.sessions',
36 | 'django.contrib.messages',
37 | ]
38 |
39 | MIDDLEWARE = (
40 | 'django.contrib.sessions.middleware.SessionMiddleware',
41 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
42 | 'django.contrib.messages.middleware.MessageMiddleware',
43 | )
44 |
45 | MIDDLEWARE_CLASSES = MIDDLEWARE
46 |
47 | TEMPLATES = [
48 | {
49 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
50 | 'DIRS': [],
51 | 'APP_DIRS': True,
52 | 'OPTIONS': {
53 | 'context_processors': [
54 | 'django.template.context_processors.debug',
55 | 'django.template.context_processors.request',
56 | 'django.template.context_processors.i18n',
57 | 'django.contrib.auth.context_processors.auth',
58 | 'django.contrib.messages.context_processors.messages',
59 | ]
60 | },
61 | }
62 | ]
63 |
--------------------------------------------------------------------------------
/django_generic_flatblocks/tests/testapp/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.conf.urls import url
3 | from django.conf.urls.static import static
4 | from django.contrib import admin
5 |
6 | admin.autodiscover()
7 |
8 | urlpatterns = [url(r'^admin/', admin.site.urls)] + static(
9 | settings.STATIC_URL, document_root=settings.STATIC_ROOT
10 | )
11 |
--------------------------------------------------------------------------------
/docs/changelog.rst:
--------------------------------------------------------------------------------
1 | .. _changelog:
2 |
3 | .. include:: ../CHANGELOG.rst
4 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # django-generic-flatblocks documentation build configuration file, created by
4 | # sphinx-quickstart on Wed Mar 23 12:45:19 2016.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import sys
16 | import os
17 |
18 | # If extensions (or modules to document with autodoc) are in another directory,
19 | # add these directories to sys.path here. If the directory is relative to the
20 | # documentation root, use os.path.abspath to make it absolute, like shown here.
21 | #sys.path.insert(0, os.path.abspath('.'))
22 |
23 | # -- General configuration ------------------------------------------------
24 |
25 | # If your documentation needs a minimal Sphinx version, state it here.
26 | #needs_sphinx = '1.0'
27 |
28 | # Add any Sphinx extension module names here, as strings. They can be
29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30 | # ones.
31 | extensions = [
32 | 'sphinx.ext.autodoc',
33 | 'sphinx.ext.viewcode',
34 | ]
35 |
36 | # Add any paths that contain templates here, relative to this directory.
37 | templates_path = ['_templates']
38 |
39 | # The suffix(es) of source filenames.
40 | # You can specify multiple suffix as a list of string:
41 | # source_suffix = ['.rst', '.md']
42 | source_suffix = '.rst'
43 |
44 | # The encoding of source files.
45 | #source_encoding = 'utf-8-sig'
46 |
47 | # The master toctree document.
48 | master_doc = 'index'
49 |
50 | # General information about the project.
51 | project = u'django-generic-flatblocks'
52 | copyright = u'2016, Martin Mahner'
53 | author = u'Martin Mahner'
54 |
55 | # The version info for the project you're documenting, acts as replacement for
56 | # |version| and |release|, also used in various other places throughout the
57 | # built documents.
58 | #
59 | # The short X.Y version.
60 | #version = u'1.0'
61 | # The full version, including alpha/beta/rc tags.
62 | #release = u'1.0'
63 |
64 | # The language for content autogenerated by Sphinx. Refer to documentation
65 | # for a list of supported languages.
66 | #
67 | # This is also used if you do content translation via gettext catalogs.
68 | # Usually you set "language" from the command line for these cases.
69 | language = None
70 |
71 | # There are two options for replacing |today|: either, you set today to some
72 | # non-false value, then it is used:
73 | #today = ''
74 | # Else, today_fmt is used as the format for a strftime call.
75 | #today_fmt = '%B %d, %Y'
76 |
77 | # List of patterns, relative to source directory, that match files and
78 | # directories to ignore when looking for source files.
79 | exclude_patterns = ['_build']
80 |
81 | # The reST default role (used for this markup: `text`) to use for all
82 | # documents.
83 | #default_role = None
84 |
85 | # If true, '()' will be appended to :func: etc. cross-reference text.
86 | #add_function_parentheses = True
87 |
88 | # If true, the current module name will be prepended to all description
89 | # unit titles (such as .. function::).
90 | #add_module_names = True
91 |
92 | # If true, sectionauthor and moduleauthor directives will be shown in the
93 | # output. They are ignored by default.
94 | #show_authors = False
95 |
96 | # The name of the Pygments (syntax highlighting) style to use.
97 | pygments_style = 'sphinx'
98 |
99 | # A list of ignored prefixes for module index sorting.
100 | #modindex_common_prefix = []
101 |
102 | # If true, keep warnings as "system message" paragraphs in the built documents.
103 | #keep_warnings = False
104 |
105 | # If true, `todo` and `todoList` produce output, else they produce nothing.
106 | todo_include_todos = False
107 |
108 |
109 | # -- Options for HTML output ----------------------------------------------
110 |
111 | import sphinx_rtd_theme
112 | html_theme = "sphinx_rtd_theme"
113 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
114 |
115 | # The theme to use for HTML and HTML Help pages. See the documentation for
116 | # a list of builtin themes.
117 | #html_theme = 'nature'
118 |
119 | # Theme options are theme-specific and customize the look and feel of a theme
120 | # further. For a list of options available for each theme, see the
121 | # documentation.
122 | #html_theme_options = {}
123 |
124 | # Add any paths that contain custom themes here, relative to this directory.
125 | #html_theme_path = []
126 |
127 | # The name for this set of Sphinx documents. If None, it defaults to
128 | # " v documentation".
129 | #html_title = None
130 |
131 | # A shorter title for the navigation bar. Default is the same as html_title.
132 | #html_short_title = None
133 |
134 | # The name of an image file (relative to this directory) to place at the top
135 | # of the sidebar.
136 | #html_logo = None
137 |
138 | # The name of an image file (relative to this directory) to use as a favicon of
139 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
140 | # pixels large.
141 | #html_favicon = None
142 |
143 | # Add any paths that contain custom static files (such as style sheets) here,
144 | # relative to this directory. They are copied after the builtin static files,
145 | # so a file named "default.css" will overwrite the builtin "default.css".
146 | #html_static_path = ['_static']
147 |
148 | # Add any extra paths that contain custom files (such as robots.txt or
149 | # .htaccess) here, relative to this directory. These files are copied
150 | # directly to the root of the documentation.
151 | #html_extra_path = []
152 |
153 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
154 | # using the given strftime format.
155 | #html_last_updated_fmt = '%b %d, %Y'
156 |
157 | # If true, SmartyPants will be used to convert quotes and dashes to
158 | # typographically correct entities.
159 | #html_use_smartypants = True
160 |
161 | # Custom sidebar templates, maps document names to template names.
162 | #html_sidebars = {}
163 |
164 | # Additional templates that should be rendered to pages, maps page names to
165 | # template names.
166 | #html_additional_pages = {}
167 |
168 | # If false, no module index is generated.
169 | #html_domain_indices = True
170 |
171 | # If false, no index is generated.
172 | #html_use_index = True
173 |
174 | # If true, the index is split into individual pages for each letter.
175 | #html_split_index = False
176 |
177 | # If true, links to the reST sources are added to the pages.
178 | #html_show_sourcelink = True
179 |
180 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
181 | #html_show_sphinx = True
182 |
183 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
184 | #html_show_copyright = True
185 |
186 | # If true, an OpenSearch description file will be output, and all pages will
187 | # contain a tag referring to it. The value of this option must be the
188 | # base URL from which the finished HTML is served.
189 | #html_use_opensearch = ''
190 |
191 | # This is the file name suffix for HTML files (e.g. ".xhtml").
192 | #html_file_suffix = None
193 |
194 | # Language to be used for generating the HTML full-text search index.
195 | # Sphinx supports the following languages:
196 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
197 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
198 | #html_search_language = 'en'
199 |
200 | # A dictionary with options for the search language support, empty by default.
201 | # Now only 'ja' uses this config value
202 | #html_search_options = {'type': 'default'}
203 |
204 | # The name of a javascript file (relative to the configuration directory) that
205 | # implements a search results scorer. If empty, the default will be used.
206 | #html_search_scorer = 'scorer.js'
207 |
208 | # Output file base name for HTML help builder.
209 | htmlhelp_basename = 'django-generic-flatblocksdoc'
210 |
211 | # -- Options for LaTeX output ---------------------------------------------
212 |
213 | latex_elements = {
214 | # The paper size ('letterpaper' or 'a4paper').
215 | #'papersize': 'letterpaper',
216 |
217 | # The font size ('10pt', '11pt' or '12pt').
218 | #'pointsize': '10pt',
219 |
220 | # Additional stuff for the LaTeX preamble.
221 | #'preamble': '',
222 |
223 | # Latex figure (float) alignment
224 | #'figure_align': 'htbp',
225 | }
226 |
227 | # Grouping the document tree into LaTeX files. List of tuples
228 | # (source start file, target name, title,
229 | # author, documentclass [howto, manual, or own class]).
230 | latex_documents = [
231 | (master_doc, 'django-generic-flatblocks.tex', u'django-generic-flatblocks Documentation',
232 | u'Martin Mahner', 'manual'),
233 | ]
234 |
235 | # The name of an image file (relative to this directory) to place at the top of
236 | # the title page.
237 | #latex_logo = None
238 |
239 | # For "manual" documents, if this is true, then toplevel headings are parts,
240 | # not chapters.
241 | #latex_use_parts = False
242 |
243 | # If true, show page references after internal links.
244 | #latex_show_pagerefs = False
245 |
246 | # If true, show URL addresses after external links.
247 | #latex_show_urls = False
248 |
249 | # Documents to append as an appendix to all manuals.
250 | #latex_appendices = []
251 |
252 | # If false, no module index is generated.
253 | #latex_domain_indices = True
254 |
255 |
256 | # -- Options for manual page output ---------------------------------------
257 |
258 | # One entry per manual page. List of tuples
259 | # (source start file, name, description, authors, manual section).
260 | man_pages = [
261 | (master_doc, 'django-generic-flatblocks', u'django-generic-flatblocks Documentation',
262 | [author], 1)
263 | ]
264 |
265 | # If true, show URL addresses after external links.
266 | #man_show_urls = False
267 |
268 |
269 | # -- Options for Texinfo output -------------------------------------------
270 |
271 | # Grouping the document tree into Texinfo files. List of tuples
272 | # (source start file, target name, title, author,
273 | # dir menu entry, description, category)
274 | texinfo_documents = [
275 | (master_doc, 'django-generic-flatblocks', u'django-generic-flatblocks Documentation',
276 | author, 'django-generic-flatblocks', 'One line description of project.',
277 | 'Miscellaneous'),
278 | ]
279 |
280 | # Documents to append as an appendix to all manuals.
281 | #texinfo_appendices = []
282 |
283 | # If false, no module index is generated.
284 | #texinfo_domain_indices = True
285 |
286 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
287 | #texinfo_show_urls = 'footnote'
288 |
289 | # If true, do not generate a @detailmenu in the "Top" node's menu.
290 | #texinfo_no_detailmenu = False
291 |
--------------------------------------------------------------------------------
/docs/contributed_nodes.rst:
--------------------------------------------------------------------------------
1 | .. _ref-contributed-nodes:
2 |
3 | =========================
4 | Contributed content nodes
5 | =========================
6 |
7 | django-generic-flatblocks comes with some very commonly used content-nodes.
8 | They are not installed by default. To do so, insert ``django_generic_flatblocks.contrib.gblocks``
9 | to your ``INSTALLED_APPS`` in your settings and resync your database:
10 | ``./manage.py syncdb``.
11 |
12 | The contributed content nodes are:
13 |
14 | - **gblocks.Title**: A CharField rendered as a
Tag.
15 |
16 | - **gblocks.Text**: A TextField rendered as html paragraphs. (This is what
17 | django-chunks provides)
18 |
19 | - **gblocks.Image**: A ImageField rendered as Tag.
20 |
21 | - **gblocks.TitleAndText**: A CharField and a TextField. (This is what
22 | django-flatblocks provides)
23 |
24 | - **gblocks.TitleTextAndImage**: A CharField, TextField and ImageField
25 |
26 | So if you want to display a title and textfield, use this templatetag for
27 | example::
28 |
29 | {% gblock "about_me" for "gblocks.TitleAndText" %}
30 |
--------------------------------------------------------------------------------
/docs/creating_nodes.rst:
--------------------------------------------------------------------------------
1 | .. _ref-creating-nodes:
2 |
3 | ============================
4 | Create your own content node
5 | ============================
6 |
7 | A content node is a simple django-model. No quirks. If you want to use a title
8 | and a textfield as your content-node, define a new model ``Entry`` in your
9 | application ``myproject``::
10 |
11 | from django.db import models
12 | from django.contrib import admin
13 | from django.utils.encoding import python_2_unicode_compatible
14 |
15 | @python_2_unicode_compatible
16 | class Entry(models.Model):
17 | title = models.CharField(max_length=255, blank=True)
18 | content = models.TextField(blank=True)
19 |
20 | def __str__(self):
21 | return self.title
22 |
23 | admin.site.register(Entry)
24 |
25 | .. important::
26 | django-generic-flatblocks creates an empty content-node upon first
27 | request, so make sure each field has either it's default value or
28 | allow ``blank=True``. Don't forget to register your Model in the
29 | admin backend, if you want to edit it there.
30 |
31 | Then create a template ``myproject/entry/flatblock.html`` in your
32 | template directory. This template is the default template to render the
33 | content node, if you do not provide a unique template for it (*with*
34 | argument).
35 |
36 | In this template are all context-variables from the *parent* template
37 | available plus some extra variables. See arguments/with above for details.
38 |
39 | A common template source for the content node would be::
40 |
41 |
{{ object.title }}
42 | {{ object.content|safe }}
43 |
44 | {% if admin_url %}edit this{% endif %}
45 |
46 | In your templates, create a new content node using the templatetag::
47 |
48 | {% gblock "about_me" for "myproject.Entry" %}
49 |
50 | For some pre defined nodes see :ref:`ref-contributed-nodes`
51 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. index:
2 |
3 | .. include:: ../README.rst
4 |
5 | Contents:
6 | =========
7 |
8 | .. toctree::
9 | :glob:
10 |
11 | installation
12 | quickstart
13 | usage
14 | creating_nodes
15 | contributed_nodes
16 | changelog
17 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | .. _installation:
2 |
3 | ============
4 | Installation
5 | ============
6 |
7 | This package is available through the python package index, pypi. You can
8 | install the latest version by::
9 |
10 | pip install django-generic-flatblocks
11 |
12 |
13 | Add the module to your ``INSTALLED_APPS`` in your settings::
14 |
15 | INSTALLED_APPS = (
16 | ...
17 | 'django_generic_flatblocks',
18 | 'django_generic_flatblocks.contrib.gblocks', # Optional sample models
19 | )
20 |
21 | Make sure that ``django.core.context_processors.request`` was added to your
22 | ``TEMPLATE`` options::
23 |
24 | TEMPLATES = [{
25 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
26 | 'OPTIONS': {
27 | 'context_processors': [
28 | 'django.template.context_processors.request',
29 | ...
30 |
31 | *(Optional)* Define the url prefix to your contrib.admin installation in the
32 | setting ``ADMIN_URL_PREFIX``. Most commonly this is ``/admin/``. Beware
33 | the trailing slash.
34 |
35 | Migrate the database schemas::
36 |
37 | ./manage.py migrate
38 |
39 | See :ref:`quickstart` for a quick demonstration or :ref:`ref-usage` for a
40 | detailed integration.
41 |
42 |
43 | Local Development
44 | =================
45 |
46 | Install the package using pipenv::
47 |
48 | $ cd django-generic-flatblocks
49 | $ pipenv install --dev
50 | $ pipenv run test
51 |
52 | You can run the testsuite against a variety of Python and Django versions with
53 | tox::
54 |
55 | $ cd django-generic-flatblocks
56 | $ tox
57 |
--------------------------------------------------------------------------------
/docs/quickstart.rst:
--------------------------------------------------------------------------------
1 | .. _quickstart:
2 |
3 | ==========
4 | Quickstart
5 | ==========
6 |
7 | You can join unlimited of slug-strings or context-variables to one slug. Most
8 | commonly you will do this if you need to use the users LANGUAGE_CODE in your
9 | slug, to have different content nodes for every language::
10 |
11 | {% load generic_flatblocks %}
12 | {% gblock "website","title",LANGUAGE_CODE for "gblocks.Title" %}
13 |
14 | The slug can also be a context variable::
15 |
16 | {% with "website_teaser" as my_slug %}
17 | {% gblock my_slug for "gblocks.Text" %}
18 | {% endwith %}
19 |
20 | You can render each generic block with a template of your choice::
21 |
22 | {% gblock "website_urgent_notice" for "gblocks.Text" with "urgent.html" %}
23 |
24 | You can pass an integer as slug. In this case, generic-flatblocks
25 | will fetch the model instance with the primary key you named in slug.
26 | Basically this is a {% include %} tag on model level::
27 |
28 | {% gblock 1 for "auth.user" with "current_user.html" %}
29 |
30 | You can store the related object directly in the context using
31 | the "into" argument. This is the quickest way to display any
32 | model. The "for" and "as" arguments are ignored::
33 |
34 | {% gblock 1 for "auth.user" into "the_user_object" %}
35 |
The first user is {{ the_user_object.username }}!
36 | {% if the_user_object_admin_url %}edit{% endif %}
37 |
38 |
39 | Let's create an flatblock with a "as" argument. We publish this
40 | block at the end of this page in a variable called ``FOOTER``::
41 |
42 | {% gblock "footer" for "gblocks.Text" as "FOOTER" %}
43 |
44 | {{ FOOTER }}
45 |
46 |
--------------------------------------------------------------------------------
/docs/usage.rst:
--------------------------------------------------------------------------------
1 | .. _ref-usage:
2 |
3 | ==============
4 | Detailed usage
5 | ==============
6 |
7 | First of all, in every template you want to use generic-flatblocks, load the
8 | templatetags library::
9 |
10 | {% load generic_flatblocks %}
11 |
12 | Then define a content node using the ``gblock`` templatetag::
13 |
14 | {% gblock "unique_slug" for "applabel.modelname" with "render/with/template.html" as "variable" %}
15 |
16 | The arguments in detail:
17 | ========================
18 |
19 | **"unique_slug"** (required):
20 | -----------------------------
21 |
22 | The slug argument defines under which
23 | *key* the content is stored in your database. You can define as many slugs
24 | as you want, just use a comma as separator. You can use context-variables as
25 | well. Examples::
26 |
27 | "homepage headline" becomes "homepage_headline"
28 | "homepage","headline" becomes "homepage_headline"
29 | "homepage_title",LANGUAGE_CODE becomes "homepage_title_en" (depends on the users locale code)
30 | "user",user.pk becomes "user_1" (depends on the primary key of the currently logged in user)
31 |
32 | You can pass an *integer* as the slug. This will cause the templatetag to fetch
33 | the model named in *for* with the primary key you named in *slug*. Example::
34 |
35 | {% gblock 1 for "auth.user" with "path/to/template.html" %}
36 |
37 | This will fetch the auth.User with the primary key 1 and renders this model
38 | object with the template "path/to/template.html". In this case, the
39 | ``generic_object`` in ``None``. Basically this is a ``{% include %}`` tag on
40 | model level. This can also be a context variable.
41 |
42 | *for* **"applabel.modelname"** (required):
43 | ------------------------------------------
44 |
45 | The *for* argument defines, what content-node (model) will be used to store
46 | and display the content. The format is *appname.modelname*. For some
47 | contributed content-nodes see :ref:`ref-contributed-nodes` below.
48 | This argument can be a context-variable.
49 |
50 | *with* **"template_path"** (optional):
51 | --------------------------------------
52 |
53 | You can define a template that is used for rendering the content node. If you
54 | do not provide any template, the default template ``//flatblock.html``
55 | is used. This argument can be a context-variable.
56 |
57 | In this template are all context-variables from the *parent* template
58 | available plus some extra variables:
59 |
60 | - ``object``: This variable is the model-instance for the generic block.
61 |
62 | - ``generic_object``: This variable is the model-instance for the generic
63 | content object itself. Mostly you don't need this.
64 |
65 | - ``admin_url``: A URL to the change view of the current object. This variable
66 | is ``None`` if the current user has no change permissions for the object.
67 |
68 | *as* **"variable name"** (optional):
69 | --------------------------------------
70 |
71 | If you provide a variable name, the *rendered content node* is stored in it.
72 | Otherwise it's displayed directly. This argument can be a context-variable.
73 |
74 | *into* **"variable_name"** (optional):
75 | --------------------------------------
76 |
77 | If you provide a variable name, the *related object* is stored in it. No
78 | template rendering is done. The *with* and the *as* arguments are ignored.
79 | This argument can be a context-variable.
80 |
81 | After calling the gblock templatetag, you have the same variables available
82 | as in the *with* template:
83 |
84 | - ``variable_name``: This variable is the model-instance for the generic block.
85 |
86 | - ``variable_name`` + ``"_genric_object"``: This variable is the model-instance for
87 | the generic content object itself. Mostly you don't need this.
88 |
89 | - ``variable_name`` + ``"_admin_url"``: A URL to the change view of the current object.
90 | This variable is ``None`` if the current user has no change permissions for
91 | the object.
92 |
93 | This is the quickest way to display any model instance or content-node
94 | directly without creating a template::
95 |
96 | {% gblock 1 for "auth.User" into "theuser" %}
97 | The first user is {{ theuser.username }}! (edit)
98 |
99 | would be rendered as::
100 |
101 | The first user is johndoe! (edit)
102 |
103 | .. note::
104 | If you have `settings.TEMPLATE_DEBUG` set to `True` and your related object
105 | does not exist, the templatetag will raise a ObjectNotFound exception. It
106 | will fail silently if you set `settings.TEMPLATE_DEBUG` to `False` and
107 | return an (empty, not saved) instance of the related model.
108 |
--------------------------------------------------------------------------------
/runtests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 |
5 | from django import setup
6 | from django.conf import settings
7 | from django.test.runner import DiscoverRunner
8 |
9 |
10 | def runtests(*test_args):
11 | # Setup settings
12 | if not settings.configured:
13 | from django_generic_flatblocks.tests.testapp import settings as TEST_SETTINGS
14 | settings.configure(**TEST_SETTINGS.__dict__)
15 | setup()
16 | test_runner = DiscoverRunner(verbosity=1)
17 | failures = test_runner.run_tests(['django_generic_flatblocks'])
18 | if failures:
19 | sys.exit(failures)
20 |
21 |
22 | if __name__ == '__main__':
23 | runtests(*sys.argv[1:])
24 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = django-generic-flatblocks
3 | version = 1.3
4 | description =
5 | A flatpages/flatblock application using generic relations to content models.
6 | long_description = file: README.rst, CHANGELOG.rst
7 | author = Martin Mahner
8 | author_email = martin@mahner.org
9 | url = https://github.com/bartTC/django-generic-flatblocks
10 | keywords = django, snippets, text, models, flatblock, flatpages
11 | license = MIT
12 | classifiers =
13 | Development Status :: 5 - Production/Stable
14 | Environment :: Web Environment
15 | Intended Audience :: Developers
16 | License :: OSI Approved :: MIT License
17 | Operating System :: OS Independent
18 | Programming Language :: Python
19 | Programming Language :: Python :: 2.7
20 | Programming Language :: Python :: 3.4
21 | Programming Language :: Python :: 3.5
22 | Programming Language :: Python :: 3.6
23 | Programming Language :: Python :: 3.7
24 | Framework :: Django
25 |
26 | [options]
27 | packages = find:
28 | include_package_data = True
29 | zip_safe = False
30 | python_requires = '>=2.7'
31 | install_requires =
32 | django>=1.8
33 | pillow
34 |
35 | [isort]
36 | known_first_party = django_generic_flatblocks
37 | default_section = THIRDPARTY
38 | sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
39 | multi_line_output = 0
40 | skip = migrations
41 |
42 | [coverage:run]
43 | source = django_generic_flatblocks
44 | branch = True
45 | omit =
46 | django_generic_flatblocks/migrations/*
47 | django_generic_flatblocks/contrib/gblocks/migrations/*
48 | django_generic_flatblocks/tests/*
49 |
50 | [coverage:report]
51 | exclude_lines =
52 | pragma: no cover
53 | def __repr__
54 |
55 | [coverage:html]
56 | directory = /tmp/coverage_report/django-generic-flatblocks
57 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from setuptools import setup
3 | setup()
4 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | toxworkdir = /tmp/tox/django-generic-flatblocks
3 | envlist =
4 | readme
5 | begin
6 | py{27}-django-{18,111}
7 | py{34,35,36,37}-django-{111,20}
8 | py{35,36,37}-django-{21}
9 | end
10 |
11 | [testenv]
12 | install_command =
13 | pip install {opts} {packages}
14 | setenv =
15 | DJANGO_SETTINGS_MODULE=django_generic_flatblocks.tests.testapp.settings
16 | commands =
17 | coverage run --append runtests.py
18 | deps=
19 | # Django versions
20 | django-18: django==1.8.*
21 | django-111: django==1.11.*
22 | django-20: django==2.0.*
23 | django-21: django==2.1.*
24 | coverage
25 |
26 | [testenv:coverage_setup]
27 | basepython=python3.6
28 | commands=
29 | coverage erase
30 |
31 | [testenv:coverage_report]
32 | basepython=python3.6
33 | commands=
34 | coverage report
35 | coverage html
36 |
37 | [testenv:readme]
38 | skip_install = True
39 | deps =
40 | docutils
41 | Pygments
42 | commands =
43 | rst2html.py --report=info --halt=warning README.rst /dev/null
44 | rst2html.py --report=info --halt=warning CHANGELOG.rst /dev/null
45 |
--------------------------------------------------------------------------------