Merge pull request #416 from nephila/hotfix/categories_admin
Fix error in category filtering when loading the form via POST
This commit is contained in:
commit
4841f47690
4 changed files with 134 additions and 46 deletions
|
@ -10,13 +10,13 @@ from django import forms
|
|||
from django.conf import settings
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from parler.forms import TranslatableModelForm
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .forms import PostAdminFormBase
|
||||
from .models import Post
|
||||
|
||||
|
||||
class PostWizardForm(TranslatableModelForm):
|
||||
class PostWizardForm(PostAdminFormBase):
|
||||
default_appconfig = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -31,6 +31,8 @@ class PostWizardForm(TranslatableModelForm):
|
|||
choices=self.fields['app_config'].widget.choices,
|
||||
)
|
||||
self.fields['app_config'].widget.attrs['disabled'] = True
|
||||
if 'categories' in self.fields:
|
||||
self.fields['categories'].queryset = self.available_categories
|
||||
|
||||
class Meta:
|
||||
model = Post
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.validators import MaxLengthValidator
|
||||
from django.utils.functional import cached_property
|
||||
from parler.forms import TranslatableModelForm
|
||||
from taggit_autosuggest.widgets import TagAutoSuggest
|
||||
|
||||
|
@ -12,7 +13,25 @@ from djangocms_blog.settings import get_setting
|
|||
from .models import BlogCategory, BlogConfig, Post
|
||||
|
||||
|
||||
class CategoryAdminForm(TranslatableModelForm):
|
||||
class ConfigFormBase(object):
|
||||
"""
|
||||
This provide the app_config property which returns the currently
|
||||
selected app_config, whether it's an instance attribute or
|
||||
passed in the request
|
||||
"""
|
||||
|
||||
@cached_property
|
||||
def app_config(self):
|
||||
if getattr(self.instance, 'app_config_id', None):
|
||||
return self.instance.app_config
|
||||
elif 'app_config' in self.initial:
|
||||
return BlogConfig.objects.get(pk=self.initial['app_config'])
|
||||
elif self.data.get('app_config', None):
|
||||
return BlogConfig.objects.get(pk=self.data['app_config'])
|
||||
return None
|
||||
|
||||
|
||||
class CategoryAdminForm(ConfigFormBase, TranslatableModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.base_fields['meta_description'].validators = [
|
||||
|
@ -33,11 +52,14 @@ class CategoryAdminForm(TranslatableModelForm):
|
|||
qs = qs.exclude(
|
||||
pk__in=[self.instance.pk] + [child.pk for child in self.instance.descendants()]
|
||||
)
|
||||
|
||||
config = None
|
||||
if getattr(self.instance, 'app_config_id', None):
|
||||
qs = qs.namespace(self.instance.app_config.namespace)
|
||||
elif 'initial' in kwargs and 'app_config' in kwargs['initial']:
|
||||
config = BlogConfig.objects.get(pk=kwargs['initial']['app_config'])
|
||||
elif 'app_config' in self.initial:
|
||||
config = BlogConfig.objects.get(pk=self.initial['app_config'])
|
||||
elif self.data.get('app_config', None):
|
||||
config = BlogConfig.objects.get(pk=self.data['app_config'])
|
||||
if config:
|
||||
qs = qs.namespace(config.namespace)
|
||||
self.fields['parent'].queryset = qs
|
||||
|
||||
|
@ -53,17 +75,31 @@ class LatestEntriesForm(forms.ModelForm):
|
|||
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
|
||||
'djangocms_blog_admin.css'),)
|
||||
'all': ('%sdjangocms_blog/css/%s' % (
|
||||
settings.STATIC_URL, 'djangocms_blog_admin.css'
|
||||
),)
|
||||
}
|
||||
|
||||
|
||||
class PostAdminForm(TranslatableModelForm):
|
||||
class PostAdminFormBase(ConfigFormBase, TranslatableModelForm):
|
||||
"""
|
||||
This provide common methods between the admin and wizard form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = '__all__'
|
||||
|
||||
@cached_property
|
||||
def available_categories(self):
|
||||
qs = BlogCategory.objects
|
||||
if self.app_config:
|
||||
return qs.namespace(self.app_config.namespace)
|
||||
return qs
|
||||
|
||||
|
||||
class PostAdminForm(PostAdminFormBase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.base_fields['meta_description'].validators = [
|
||||
MaxLengthValidator(get_setting('META_DESCRIPTION_LENGTH'))
|
||||
|
@ -79,26 +115,16 @@ class PostAdminForm(TranslatableModelForm):
|
|||
MaxLengthValidator(get_setting('META_TITLE_LENGTH'))
|
||||
]
|
||||
super(PostAdminForm, self).__init__(*args, **kwargs)
|
||||
|
||||
qs = BlogCategory.objects
|
||||
|
||||
config = None
|
||||
if getattr(self.instance, 'app_config_id', None):
|
||||
qs = qs.namespace(self.instance.app_config.namespace)
|
||||
elif 'initial' in kwargs and 'app_config' in kwargs['initial']:
|
||||
config = BlogConfig.objects.get(pk=kwargs['initial']['app_config'])
|
||||
qs = qs.namespace(config.namespace)
|
||||
|
||||
if 'categories' in self.fields:
|
||||
self.fields['categories'].queryset = qs
|
||||
self.fields['categories'].queryset = self.available_categories
|
||||
|
||||
if 'app_config' in self.fields:
|
||||
# Don't allow app_configs to be added here. The correct way to add an
|
||||
# apphook-config is to create an apphook on a cms Page.
|
||||
self.fields['app_config'].widget.can_add_related = False
|
||||
|
||||
if config:
|
||||
if self.app_config:
|
||||
self.initial['main_image_full'] = \
|
||||
config.app_data['config'].get('default_image_full')
|
||||
self.app_config.app_data['config'].get('default_image_full')
|
||||
self.initial['main_image_thumbnail'] = \
|
||||
config.app_data['config'].get('default_image_thumbnail')
|
||||
self.app_config.app_data['config'].get('default_image_thumbnail')
|
||||
|
|
|
@ -15,6 +15,7 @@ from django.contrib.auth.models import AnonymousUser
|
|||
from django.contrib.messages.middleware import MessageMiddleware
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import QueryDict
|
||||
from django.test import override_settings
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import strip_tags
|
||||
|
@ -181,13 +182,32 @@ class AdminTest(BaseTest):
|
|||
def test_admin_category_views(self):
|
||||
category_admin = admin.site._registry[BlogCategory]
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/', edit=False)
|
||||
BlogCategory.objects.create(name='category 1 - blog 2', app_config=self.app_config_2)
|
||||
|
||||
# Add view only has an empty form - no type
|
||||
response = category_admin.add_view(request)
|
||||
self.assertNotContains(response, 'id="id_name" maxlength="767" name="name" type="text" value="category 1"')
|
||||
self.assertContains(response, '<option value="%s">Blog / sample_app</option>' % self.app_config_1.pk)
|
||||
|
||||
# Add view select categories on the given appconfig, even when reloading the form
|
||||
request.POST = QueryDict('app_config=1')
|
||||
request.method = 'POST'
|
||||
response = category_admin.add_view(request)
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['parent'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
|
||||
request.GET = QueryDict('app_config=1')
|
||||
request.method = 'GET'
|
||||
response = category_admin.add_view(request)
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['parent'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
|
||||
# Changeview is 'normal', with a few preselected items
|
||||
request.GET = QueryDict()
|
||||
response = category_admin.change_view(request, str(self.category_1.pk))
|
||||
self.assertContains(response, 'id="id_name" maxlength="767" name="name" type="text" value="category 1"')
|
||||
self.assertContains(response, 'id="id_meta_description" maxlength="320"')
|
||||
|
@ -240,31 +260,25 @@ class AdminTest(BaseTest):
|
|||
|
||||
# Add view shows all the exising categories
|
||||
response = post_admin.add_view(request)
|
||||
self.assertContains(response, '<option value="1">category 1</option>')
|
||||
self.assertContains(response, '<option value="2">tree category 1</option>')
|
||||
self.assertContains(response, '<option value="3">tree category 2</option>')
|
||||
self.assertContains(response, '<option value="4">tree category 3</option>')
|
||||
self.assertContains(response, '<option value="5">tree category 4</option>')
|
||||
self.assertNotContains(response, 'category different branch</option>')
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['parent'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
|
||||
# Changeview hides the children of the current category
|
||||
response = post_admin.change_view(request, str(category2.pk))
|
||||
self.assertContains(response, '<option value="1">category 1</option>')
|
||||
self.assertContains(response, '<option value="2" selected="selected">tree category 1</option>')
|
||||
self.assertNotContains(response, '<option value="3">tree category 2</option>')
|
||||
self.assertNotContains(response, '<option value="4">tree category 3</option>')
|
||||
self.assertNotContains(response, '<option value="5">tree category 4</option>')
|
||||
self.assertNotContains(response, 'category different branch</option>')
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['parent'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1, parent__isnull=True)
|
||||
)
|
||||
|
||||
# Test second apphook categories
|
||||
request = self.get_page_request('/', self.user, r'/en/blog/?app_config=%s' % self.app_config_2.pk, edit=False)
|
||||
response = post_admin.add_view(request)
|
||||
self.assertNotContains(response, '<option value="1">category 1</option>')
|
||||
self.assertNotContains(response, '<option value="2">tree category 1</option>')
|
||||
self.assertNotContains(response, '<option value="3">tree category 2</option>')
|
||||
self.assertNotContains(response, '<option value="4">tree category 3</option>')
|
||||
self.assertNotContains(response, '<option value="5">tree category 4</option>')
|
||||
self.assertContains(response, 'category different branch</option>')
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['parent'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_2)
|
||||
)
|
||||
|
||||
def test_admin_fieldsets(self):
|
||||
post_admin = admin.site._registry[Post]
|
||||
|
@ -339,13 +353,31 @@ class AdminTest(BaseTest):
|
|||
msg_mid.process_request(request)
|
||||
post_admin = admin.site._registry[Post]
|
||||
response = post_admin.add_view(request)
|
||||
self.assertContains(response, '<option value="%s">%s</option>' % (
|
||||
self.category_1.pk, self.category_1.safe_translation_getter('name', language_code='en')
|
||||
))
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['categories'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
self.assertContains(response, 'id="id_sites" name="sites"')
|
||||
self.assertContains(response, 'selected="selected">Blog image')
|
||||
self.assertContains(response, 'selected="selected">Blog thumbnail')
|
||||
|
||||
# Add view select categories on the given appconfig, even when reloading the form
|
||||
request.POST = QueryDict('app_config=1')
|
||||
request.method = 'POST'
|
||||
response = post_admin.add_view(request)
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['categories'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
|
||||
request.GET = QueryDict('app_config=1')
|
||||
request.method = 'GET'
|
||||
response = post_admin.add_view(request)
|
||||
self.assertTrue(
|
||||
response.context_data['adminform'].form.fields['categories'].queryset,
|
||||
BlogCategory.objects.filter(app_config=self.app_config_1)
|
||||
)
|
||||
|
||||
self.user.sites.add(self.site_1)
|
||||
with self.login_user_context(self.user):
|
||||
request = self.get_request('/', 'en', user=self.user,
|
||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
import sys
|
||||
|
||||
from djangocms_blog.models import BlogCategory
|
||||
|
||||
from .base import BaseTest
|
||||
|
||||
|
||||
|
@ -41,6 +43,12 @@ class WizardTest(BaseTest):
|
|||
from djangocms_blog.models import Post
|
||||
self.get_pages()
|
||||
|
||||
cat_1 = BlogCategory.objects.create(name='category 1 - blog 1', app_config=self.app_config_1)
|
||||
cat_2 = BlogCategory.objects.create(name='category 1 - blog 2', app_config=self.app_config_2)
|
||||
cats = {
|
||||
self.app_config_1.pk: cat_1,
|
||||
self.app_config_2.pk: cat_2,
|
||||
}
|
||||
with current_user(self.user_staff):
|
||||
wizs = [entry for entry in wizard_pool.get_entries() if entry.model == Post]
|
||||
for index, wiz in enumerate(wizs):
|
||||
|
@ -52,7 +60,7 @@ class WizardTest(BaseTest):
|
|||
form = wiz.form(data={
|
||||
'1-title': 'title{0}'.format(index),
|
||||
'1-abstract': 'abstract{0}'.format(index),
|
||||
'1-categories': [self.category_1.pk],
|
||||
'1-categories': [cats[app_config].pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, app_config)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
@ -66,7 +74,7 @@ class WizardTest(BaseTest):
|
|||
form = wiz.form(data={
|
||||
'1-title': 'title-2{0}'.format(index),
|
||||
'1-abstract': 'abstract-2{0}'.format(index),
|
||||
'1-categories': [self.category_1.pk],
|
||||
'1-categories': [cats[app_config].pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, app_config)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
@ -74,6 +82,26 @@ class WizardTest(BaseTest):
|
|||
instance = form.save()
|
||||
self.assertEqual(instance.author, self.user_normal)
|
||||
|
||||
def test_wizard_init_categories_check(self):
|
||||
from cms.utils.permissions import current_user
|
||||
from cms.wizards.wizard_pool import wizard_pool
|
||||
from djangocms_blog.models import Post
|
||||
self.get_pages()
|
||||
|
||||
with current_user(self.user_staff):
|
||||
wiz = None
|
||||
for wiz in wizard_pool.get_entries():
|
||||
if wiz.model == Post and wiz.title == 'New Article':
|
||||
break
|
||||
form = wiz.form(data={
|
||||
'1-title': 'title article',
|
||||
'1-abstract': 'abstract article',
|
||||
'1-categories': [self.category_1.pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, self.app_config_2.pk)
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertTrue('categories' in form.errors.keys())
|
||||
|
||||
def test_wizard_import(self):
|
||||
# The following import should not fail in any django CMS version
|
||||
pass
|
||||
|
|
Loading…
Add table
Reference in a new issue