Commit 464b503b by Ned Batchelder Committed by Sarina Canelake

Use lazy translations for i18n

parent d4b80025
from __future__ import unicode_literals from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
"""Base classes for different plugin objects. """Base classes for different plugin objects.
......
...@@ -8,7 +8,6 @@ from datetime import timedelta ...@@ -8,7 +8,6 @@ from datetime import timedelta
from django.utils import timezone from django.utils import timezone
from django import forms from django import forms
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.forms.util import flatatt from django.forms.util import flatatt
...@@ -55,7 +54,7 @@ class SpamProtectionMixin(): ...@@ -55,7 +54,7 @@ class SpamProtectionMixin():
ip_address = request.META.get('REMOTE_ADDR', None) ip_address = request.META.get('REMOTE_ADDR', None)
if not (user or ip_address): if not (user or ip_address):
raise forms.ValidationError(ugettext('Spam protection failed to find both a logged in user and an IP address.')) raise forms.ValidationError(_('Spam protection failed to find both a logged in user and an IP address.'))
def check_interval(from_time, max_count, interval_name): def check_interval(from_time, max_count, interval_name):
from_time = timezone.now() - timedelta(minutes=settings.REVISIONS_MINUTES_LOOKBACK) from_time = timezone.now() - timedelta(minutes=settings.REVISIONS_MINUTES_LOOKBACK)
...@@ -68,7 +67,7 @@ class SpamProtectionMixin(): ...@@ -68,7 +67,7 @@ class SpamProtectionMixin():
revisions = revisions.filter(ip_address=ip_address) revisions = revisions.filter(ip_address=ip_address)
revisions = revisions.count() revisions = revisions.count()
if revisions >= max_count: if revisions >= max_count:
raise forms.ValidationError(ugettext('Spam protection: You are only allowed to create or edit %(revisions)d article(s) per %(interval_name)s.') % raise forms.ValidationError(_('Spam protection: You are only allowed to create or edit %(revisions)d article(s) per %(interval_name)s.') %
{'revisions': max_count, {'revisions': max_count,
'interval_name': interval_name,}) 'interval_name': interval_name,})
...@@ -162,9 +161,9 @@ class EditForm(forms.Form, SpamProtectionMixin): ...@@ -162,9 +161,9 @@ class EditForm(forms.Form, SpamProtectionMixin):
if self.no_clean or self.preview: if self.no_clean or self.preview:
return cd return cd
if not str(self.initial_revision.id) == str(self.presumed_revision): if not str(self.initial_revision.id) == str(self.presumed_revision):
raise forms.ValidationError(ugettext('While you were editing, someone else changed the revision. Your contents have been automatically merged with the new contents. Please review the text below.')) raise forms.ValidationError(_('While you were editing, someone else changed the revision. Your contents have been automatically merged with the new contents. Please review the text below.'))
if cd['title'] == self.initial_revision.title and cd['content'] == self.initial_revision.content: if cd['title'] == self.initial_revision.title and cd['content'] == self.initial_revision.content:
raise forms.ValidationError(ugettext('No changes made. Nothing to save.')) raise forms.ValidationError(_('No changes made. Nothing to save.'))
self.check_spam() self.check_spam()
return cd return cd
...@@ -266,9 +265,9 @@ class CreateForm(forms.Form, SpamProtectionMixin): ...@@ -266,9 +265,9 @@ class CreateForm(forms.Form, SpamProtectionMixin):
def clean_slug(self): def clean_slug(self):
slug = self.cleaned_data['slug'] slug = self.cleaned_data['slug']
if slug.startswith("_"): if slug.startswith("_"):
raise forms.ValidationError(ugettext('A slug may not begin with an underscore.')) raise forms.ValidationError(_('A slug may not begin with an underscore.'))
if slug == 'admin': if slug == 'admin':
raise forms.ValidationError(ugettext("'admin' is not a permitted slug name.")) raise forms.ValidationError(_("'admin' is not a permitted slug name."))
if settings.URL_CASE_SENSITIVE: if settings.URL_CASE_SENSITIVE:
already_existing_slug = models.URLPath.objects.filter(slug=slug, parent=self.urlpath_parent) already_existing_slug = models.URLPath.objects.filter(slug=slug, parent=self.urlpath_parent)
...@@ -279,16 +278,16 @@ class CreateForm(forms.Form, SpamProtectionMixin): ...@@ -279,16 +278,16 @@ class CreateForm(forms.Form, SpamProtectionMixin):
if already_existing_slug: if already_existing_slug:
already_urlpath = already_existing_slug[0] already_urlpath = already_existing_slug[0]
if already_urlpath.article and already_urlpath.article.current_revision.deleted: if already_urlpath.article and already_urlpath.article.current_revision.deleted:
raise forms.ValidationError(ugettext('A deleted article with slug "%s" already exists.') % already_urlpath.slug) raise forms.ValidationError(_('A deleted article with slug "%s" already exists.') % already_urlpath.slug)
else: else:
raise forms.ValidationError(ugettext('A slug named "%s" already exists.') % already_urlpath.slug) raise forms.ValidationError(_('A slug named "%s" already exists.') % already_urlpath.slug)
if settings.CHECK_SLUG_URL_AVAILABLE: if settings.CHECK_SLUG_URL_AVAILABLE:
try: try:
# Fail validation if URL resolves to non-wiki app # Fail validation if URL resolves to non-wiki app
match = resolve(self.urlpath_parent.path + '/' + slug + '/') match = resolve(self.urlpath_parent.path + '/' + slug + '/')
if match.app_name != 'wiki': if match.app_name != 'wiki':
raise forms.ValidationError(ugettext('This slug conflicts with an existing URL.')) raise forms.ValidationError(_('This slug conflicts with an existing URL.'))
except Resolver404: except Resolver404:
pass pass
...@@ -317,9 +316,9 @@ class DeleteForm(forms.Form): ...@@ -317,9 +316,9 @@ class DeleteForm(forms.Form):
def clean(self): def clean(self):
cd = self.cleaned_data cd = self.cleaned_data
if not cd['confirm']: if not cd['confirm']:
raise forms.ValidationError(ugettext('You are not sure enough!')) raise forms.ValidationError(_('You are not sure enough!'))
if cd['revision'] != self.article.current_revision: if cd['revision'] != self.article.current_revision:
raise forms.ValidationError(ugettext('While you tried to delete this article, it was modified. TAKE CARE!')) raise forms.ValidationError(_('While you tried to delete this article, it was modified. TAKE CARE!'))
return cd return cd
...@@ -336,8 +335,9 @@ class PermissionsForm(PluginSettingsFormMixin, forms.ModelForm): ...@@ -336,8 +335,9 @@ class PermissionsForm(PluginSettingsFormMixin, forms.ModelForm):
help_text=_('Enter the username of the owner.')) help_text=_('Enter the username of the owner.'))
group = forms.ModelChoiceField(models.Group.objects.all(), empty_label=_('(none)'), group = forms.ModelChoiceField(models.Group.objects.all(), empty_label=_('(none)'),
label=_('Group'), required=False) label=_('Group'), required=False)
if settings.USE_BOOTSTRAP_SELECT_WIDGET: if settings.USE_BOOTSTRAP_SELECT_WIDGET:
group.widget= SelectWidgetBootstrap() group.widget = SelectWidgetBootstrap()
recursive = forms.BooleanField(label=_('Inherit permissions'), help_text=_('Check here to apply the above permissions (excluding group and owner of the article) recursively to articles below this one.'), recursive = forms.BooleanField(label=_('Inherit permissions'), help_text=_('Check here to apply the above permissions (excluding group and owner of the article) recursively to articles below this one.'),
required=False) required=False)
...@@ -403,7 +403,7 @@ class PermissionsForm(PluginSettingsFormMixin, forms.ModelForm): ...@@ -403,7 +403,7 @@ class PermissionsForm(PluginSettingsFormMixin, forms.ModelForm):
kwargs = {User.USERNAME_FIELD: username} kwargs = {User.USERNAME_FIELD: username}
user = User.objects.get(**kwargs) user = User.objects.get(**kwargs)
except User.DoesNotExist: except User.DoesNotExist:
raise forms.ValidationError(ugettext('No user with that username')) raise forms.ValidationError(_('No user with that username'))
else: else:
user = None user = None
else: else:
......
...@@ -22,7 +22,7 @@ except: ...@@ -22,7 +22,7 @@ except:
notrans=transaction.commit_manually notrans=transaction.commit_manually
from django.db.models.signals import post_save, pre_delete from django.db.models.signals import post_save, pre_delete
from django.utils.translation import ugettext_lazy as _, ugettext from django.utils.translation import ugettext_lazy as _
from mptt.fields import TreeForeignKey from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel from mptt.models import MPTTModel
...@@ -161,7 +161,7 @@ class URLPath(MPTTModel): ...@@ -161,7 +161,7 @@ class URLPath(MPTTModel):
def __str__(self): def __str__(self):
path = self.path path = self.path
return path if path else ugettext("(root)") return path if path else _("(root)")
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super(URLPath, self).save(*args, **kwargs) super(URLPath, self).save(*args, **kwargs)
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django import forms from django import forms
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from wiki.plugins.attachments import models from wiki.plugins.attachments import models
...@@ -102,14 +101,14 @@ class AttachmentArchiveForm(AttachmentForm): ...@@ -102,14 +101,14 @@ class AttachmentArchiveForm(AttachmentForm):
except IllegalFileExtension as e: except IllegalFileExtension as e:
raise forms.ValidationError(e) raise forms.ValidationError(e)
except zipfile.BadZipfile: except zipfile.BadZipfile:
raise forms.ValidationError(ugettext("Not a zip file")) raise forms.ValidationError(_("Not a zip file"))
else: else:
return super(AttachmentArchiveForm, self).clean_file() return super(AttachmentArchiveForm, self).clean_file()
return uploaded_file return uploaded_file
def clean(self): def clean(self):
if not can_moderate(self.article, self.request.user): if not can_moderate(self.article, self.request.user):
raise forms.ValidationError(ugettext("User not allowed to moderate this article")) raise forms.ValidationError(_("User not allowed to moderate this article"))
return self.cleaned_data return self.cleaned_data
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
...@@ -157,7 +156,7 @@ class DeleteForm(forms.Form): ...@@ -157,7 +156,7 @@ class DeleteForm(forms.Form):
def clean_confirm(self): def clean_confirm(self):
if not self.cleaned_data['confirm']: if not self.cleaned_data['confirm']:
raise forms.ValidationError(ugettext('You are not sure enough!')) raise forms.ValidationError(_('You are not sure enough!'))
return True return True
class SearchForm(forms.Form): class SearchForm(forms.Form):
......
...@@ -8,6 +8,8 @@ from django.template.context import Context ...@@ -8,6 +8,8 @@ from django.template.context import Context
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from wiki.core.permissions import can_read from wiki.core.permissions import can_read
from django.utils.translation import ugettext_lazy as _
ATTACHMENT_RE = re.compile(r'(?P<before>.*)(\[attachment\:(?P<id>\d+)\])(?P<after>.*)', re.IGNORECASE) ATTACHMENT_RE = re.compile(r'(?P<before>.*)(\[attachment\:(?P<id>\d+)\])(?P<after>.*)', re.IGNORECASE)
...@@ -60,7 +62,9 @@ class AttachmentPreprocessor(markdown.preprocessors.Preprocessor): ...@@ -60,7 +62,9 @@ class AttachmentPreprocessor(markdown.preprocessors.Preprocessor):
})) }))
line = self.markdown.htmlStash.store(html, safe=True) line = self.markdown.htmlStash.store(html, safe=True)
except models.Attachment.DoesNotExist: except models.Attachment.DoesNotExist:
html = """<span class="attachment attachment-deleted">Attachment with ID #%s is deleted.</span>""" % attachment_id html = """<span class="attachment attachment-deleted">{text}</span>""".format(
text=_("Attachment with ID #{id_number} is deleted.").format(id_number=attachment_id)
)
line = line.replace(m.group(2), self.markdown.htmlStash.store(html, safe=True)) line = line.replace(m.group(2), self.markdown.htmlStash.store(html, safe=True))
line = before + line + after line = before + line + after
new_text.append(line) new_text.append(line)
......
...@@ -4,7 +4,6 @@ from __future__ import absolute_import ...@@ -4,7 +4,6 @@ from __future__ import absolute_import
import os.path import os.path
from django.db import models from django.db import models
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.conf import settings as django_settings from django.conf import settings as django_settings
...@@ -60,9 +59,9 @@ def extension_allowed(filename): ...@@ -60,9 +59,9 @@ def extension_allowed(filename):
extension = filename.split(".")[-1] extension = filename.split(".")[-1]
except IndexError: except IndexError:
# No extension # No extension
raise IllegalFileExtension(ugettext("No file extension found in filename. That's not okay!")) raise IllegalFileExtension(_("No file extension found in filename. That's not okay!"))
if not extension.lower() in map(lambda x: x.lower(), settings.FILE_EXTENSIONS): if not extension.lower() in map(lambda x: x.lower(), settings.FILE_EXTENSIONS):
raise IllegalFileExtension(ugettext("The following filename is illegal: %s. Extension has to be one of %s") % raise IllegalFileExtension(_("The following filename is illegal: %s. Extension has to be one of %s") %
(filename, ", ".join(settings.FILE_EXTENSIONS))) (filename, ", ".join(settings.FILE_EXTENSIONS)))
return extension return extension
......
...@@ -6,7 +6,7 @@ from django.db.models import Q ...@@ -6,7 +6,7 @@ from django.db.models import Q
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView, View from django.views.generic.base import TemplateView, View
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.views.generic.list import ListView from django.views.generic.list import ListView
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django.conf.urls import patterns, url, include from django.conf.urls import patterns, url, include
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry from wiki.core.plugins import registry
from wiki.core.plugins.base import BasePlugin from wiki.core.plugins.base import BasePlugin
......
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry from wiki.core.plugins import registry
from wiki.core.plugins.base import BasePlugin from wiki.core.plugins.base import BasePlugin
......
from __future__ import unicode_literals from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django import forms from django import forms
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins.base import PluginSidebarFormMixin from wiki.core.plugins.base import PluginSidebarFormMixin
...@@ -17,7 +16,9 @@ class SidebarForm(PluginSidebarFormMixin): ...@@ -17,7 +16,9 @@ class SidebarForm(PluginSidebarFormMixin):
self.fields['image'].required = True self.fields['image'].required = True
def get_usermessage(self): def get_usermessage(self):
return ugettext("New image %s was successfully uploaded. You can use it by selecting it from the list of available images.") % self.instance.get_filename() return _("New image {image_name} was successfully uploaded. You can use it by selecting it from the list of available images.").format(
image_name=self.instance.get_filename()
)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.instance.id: if not self.instance.id:
...@@ -66,5 +67,5 @@ class PurgeForm(forms.Form): ...@@ -66,5 +67,5 @@ class PurgeForm(forms.Form):
def clean_confirm(self): def clean_confirm(self):
confirm = self.cleaned_data['confirm'] confirm = self.cleaned_data['confirm']
if not confirm: if not confirm:
raise forms.ValidationError(ugettext('You are not sure enough!')) raise forms.ValidationError(_('You are not sure enough!'))
return confirm return confirm
...@@ -4,7 +4,7 @@ from django.contrib import messages ...@@ -4,7 +4,7 @@ from django.contrib import messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from django.views.generic.list import ListView from django.views.generic.list import ListView
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry from wiki.core.plugins import registry
from wiki.core.plugins.base import BasePlugin from wiki.core.plugins.base import BasePlugin
......
...@@ -2,7 +2,7 @@ from __future__ import absolute_import ...@@ -2,7 +2,7 @@ from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry from wiki.core.plugins import registry
from wiki.core.plugins.base import BasePlugin from wiki.core.plugins.base import BasePlugin
......
...@@ -2,7 +2,6 @@ from __future__ import unicode_literals ...@@ -2,7 +2,6 @@ from __future__ import unicode_literals
from __future__ import absolute_import from __future__ import absolute_import
from django import forms from django import forms
from django.forms.models import modelformset_factory, BaseModelFormSet from django.forms.models import modelformset_factory, BaseModelFormSet
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_nyt.models import Settings, NotificationType, Subscription from django_nyt.models import Settings, NotificationType, Subscription
...@@ -17,7 +16,7 @@ from wiki.plugins.notifications import models ...@@ -17,7 +16,7 @@ from wiki.plugins.notifications import models
class SettingsModelChoiceField(forms.ModelChoiceField): class SettingsModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj): def label_from_instance(self, obj):
return ugettext( return _(
"Receive notifications %(interval)s" "Receive notifications %(interval)s"
) % { ) % {
'interval': obj.get_interval_display() 'interval': obj.get_interval_display()
...@@ -27,7 +26,7 @@ class SettingsModelChoiceField(forms.ModelChoiceField): ...@@ -27,7 +26,7 @@ class SettingsModelChoiceField(forms.ModelChoiceField):
class ArticleSubscriptionModelMultipleChoiceField(forms.ModelMultipleChoiceField): class ArticleSubscriptionModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj): def label_from_instance(self, obj):
return ugettext("%(title)s - %(url)s") % { return _("%(title)s - %(url)s") % {
'title': obj.article.current_revision.title, 'title': obj.article.current_revision.title,
'url': obj.article.get_absolute_url() 'url': obj.article.get_absolute_url()
} }
...@@ -42,17 +41,17 @@ class SettingsModelForm(forms.ModelForm): ...@@ -42,17 +41,17 @@ class SettingsModelForm(forms.ModelForm):
self.__editing_instance = True self.__editing_instance = True
self.fields['delete_subscriptions'] = ArticleSubscriptionModelMultipleChoiceField( self.fields['delete_subscriptions'] = ArticleSubscriptionModelMultipleChoiceField(
models.ArticleSubscription.objects.filter(subscription__settings=instance), models.ArticleSubscription.objects.filter(subscription__settings=instance),
label=ugettext("Remove subscriptions"), label=_("Remove subscriptions"),
required=False, required=False,
help_text=ugettext("Select article subscriptions to remove from notifications"), help_text=_("Select article subscriptions to remove from notifications"),
initial = models.ArticleSubscription.objects.none(), initial = models.ArticleSubscription.objects.none(),
) )
self.fields['email'] = forms.TypedChoiceField( self.fields['email'] = forms.TypedChoiceField(
label=_("Email digests"), label=_("Email digests"),
choices = ( choices = (
(0, ugettext('Unchanged (selected on each article)')), (0, _('Unchanged (selected on each article)')),
(1, ugettext('No emails')), (1, _('No emails')),
(2, ugettext('Email on any change')), (2, _('Email on any change')),
), ),
coerce=lambda x: int(x) if not x is None else None, coerce=lambda x: int(x) if not x is None else None,
widget=forms.RadioSelect(), widget=forms.RadioSelect(),
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
{% load wiki_tags i18n %} {% load wiki_tags i18n %}
{% if not hidedate %}{{ revision.created }}{% endif %} {% if not hidenumber %}(#{{ revision.revision_number }}) {% trans "by" %}{% endif %} {% if revision.user %}{{ revision.user }}{% else %}{% if article|can_moderate:user %}{{ revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %} {% if not hidedate %}{{ revision.created }}{% endif %} {% if not hidenumber %}(#{{ revision.revision_number }}) {% trans "by" %}{% endif %} {% if revision.user %}{{ revision.user }}{% else %}{% if article|can_moderate:user %}{{ revision.ip_address|default:_("anonymous (IP not logged)") }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
{% if revision == current_revision %} {% if revision == current_revision %}
<strong>*</strong> <strong>*</strong>
{% endif %} {% endif %}
......
...@@ -19,7 +19,8 @@ from django.contrib.auth.forms import AuthenticationForm ...@@ -19,7 +19,8 @@ from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.shortcuts import redirect, render_to_response from django.shortcuts import redirect, render_to_response
from django.template.context import RequestContext from django.template.context import RequestContext
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import View from django.views.generic.base import View
from django.views.generic.edit import CreateView, FormView from django.views.generic.edit import CreateView, FormView
......
...@@ -11,7 +11,7 @@ from django.db import transaction ...@@ -11,7 +11,7 @@ from django.db import transaction
from django.shortcuts import render_to_response, redirect, get_object_or_404 from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template.context import RequestContext from django.template.context import RequestContext
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView, View, RedirectView from django.views.generic.base import TemplateView, View, RedirectView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.views.generic.list import ListView from django.views.generic.list import ListView
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment