Skip to content

Instantly share code, notes, and snippets.

@Kniyl
Last active August 29, 2015 14:00
Show Gist options
  • Save Kniyl/11249940 to your computer and use it in GitHub Desktop.
Save Kniyl/11249940 to your computer and use it in GitHub Desktop.
reusable django app to create django-modeltranslation fields into mezzanine models
from copy import deepcopy
from django.contrib import admin
from django.utils.translation import activate, get_language
from modeltranslation.admin import TranslationAdmin, TranslationTabularInline
from mezzanine.conf import settings
from mezzanine.core.admin import TabularDynamicInlineAdmin
applications = settings.INSTALLED_APPS
def save_obj_for_every_language(obj):
"""
When ``Displayable`` are saved, they auto-populate some fields.
Do it for every languages.
"""
lang = get_language()
for code, _ in settings.LANGUAGES:
try:
activate(code)
except:
pass
else:
obj.save()
activate(lang)
if "mezzanine.pages" in applications:
from mezzanine.pages.models import Page, Link, RichTextPage
from mezzanine.pages.admin import PageAdmin, LinkAdmin
class TranslatedPageAdmin(PageAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedPageAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedPageAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
# Avoid 'content' fields to be displayed twice
richtextpage_fieldsets = deepcopy(PageAdmin.fieldsets)
richtextpage_fieldsets[0][1]["fields"].insert(3, "content")
class TranslatedRichTextPageAdmin(TranslatedPageAdmin):
fieldsets = richtextpage_fieldsets
class TranslatedLinkAdmin(LinkAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedLinkAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedLinkAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
admin.site.unregister(Page)
admin.site.unregister(RichTextPage)
admin.site.unregister(Link)
admin.site.register(Page, TranslatedPageAdmin)
admin.site.register(RichTextPage, TranslatedRichTextPageAdmin)
admin.site.register(Link, TranslatedLinkAdmin)
if "mezzanine.galleries" in applications:
from mezzanine.galleries.models import Gallery, GalleryImage
from mezzanine.galleries.admin import GalleryAdmin, GalleryImageInline
# If no inline class, the original 'description' field is still displayed
class TranslatedGalleryImageInline(GalleryImageInline, TranslationTabularInline):
# If no fieldsets, the translated 'description' fields are displayed twice
fieldsets = ((None, {"fields": ('file', 'description')}),)
# Avoid 'content' fields to be displayed twice
gallery_fieldsets = deepcopy(GalleryAdmin.fieldsets)
gallery_fieldsets[0][1]["fields"].insert(3, "content")
class TranslatedGalleryAdmin(GalleryAdmin, TranslationAdmin):
fieldsets = gallery_fieldsets
inlines = (TranslatedGalleryImageInline,)
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedGalleryAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedGalleryAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
admin.site.unregister(Gallery)
admin.site.register(Gallery, TranslatedGalleryAdmin)
if "mezzanine.forms" in applications:
from mezzanine.forms.models import Form
from mezzanine.forms.admin import FormAdmin, FieldAdmin
# Same as GalleryImageInline
field_fieldsets = ((None, {"fields": ['label', 'field_type', 'required', 'visible', 'choices', 'default', 'help_text']}),)
if settings.FORMS_USE_HTML5:
field_fieldsets[0][1]["fields"].insert(6, 'placeholder_text')
class TranslatedFieldInline(FieldAdmin, TranslationTabularInline):
fieldsets = field_fieldsets
class TranslatedFormAdmin(FormAdmin, TranslationAdmin):
inlines = (TranslatedFieldInline,)
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedFormAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedFormAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
admin.site.unregister(Form)
admin.site.register(Form, TranslatedFormAdmin)
if "mezzanine.blog" in applications:
from mezzanine.blog.models import BlogPost, BlogCategory
from mezzanine.blog.admin import BlogPostAdmin, BlogCategoryAdmin
class TranslatedBlogPostAdmin(BlogPostAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedBlogPostAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedBlogPostAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
class TranslatedBlogCategoryAdmin(BlogCategoryAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedBlogCategoryAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
admin.site.unregister(BlogPost)
admin.site.unregister(BlogCategory)
admin.site.register(BlogPost, TranslatedBlogPostAdmin)
admin.site.register(BlogCategory, TranslatedBlogCategoryAdmin)
if "cartridge.shop" in applications:
from cartridge.shop.models import Category, Product, ProductOption, ProductImage, ProductVariation
from cartridge.shop.admin import CategoryAdmin, ProductAdmin, ProductOptionAdmin, ProductImageAdmin, option_fields
from mezzanine.core.models import CONTENT_STATUS_DRAFT
class TranslatedCategoryAdmin(CategoryAdmin, TranslationAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedCategoryAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_model(self, request, obj, form, change):
super(TranslatedCategoryAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
class TranslatedOptionAdmin(ProductOptionAdmin, TranslationAdmin):
pass
class TranslatedProductImageInline(ProductImageAdmin, TranslationTabularInline):
fieldsets = ((None, {"fields": ('file', 'description',)}),)
class TranslatedProductAdmin(ProductAdmin, TranslationAdmin):
inlines = (TranslatedProductImageInline,) + deepcopy(ProductAdmin.inlines[1:])
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(TranslatedProductAdmin, self).formfield_for_dbfield(db_field, **kwargs)
self.patch_translation_field(db_field, field, **kwargs)
return field
def save_formset(self, request, form, formset, change):
"""
Add an additionnal pass to save every translated fields from
``ProdcutOption`` into the required ``ProductVariation``.
"""
super(TranslatedProductAdmin, self).save_formset(request, form, formset, change)
if formset.model == ProductVariation:
for option_name in option_fields:
for option_value in request.POST.getlist(option_name):
# Option name is declared as "option%s" % type
option_model = ProductOption.objects.get(type=option_name[6:], name=option_value)
for var in eval('self._product.variations.filter('+option_name+'="'+option_value+'")'):
for code, _ in settings.LANGUAGES:
exec("var."+option_name+"_"+code+" = option_model.name_"+code)
var.save()
def save_model(self, request, obj, form, change):
super(TranslatedProductAdmin, self).save_model(request, obj, form, change)
save_obj_for_every_language(obj)
admin.site.unregister(Category)
admin.site.unregister(Product)
admin.site.unregister(ProductOption)
admin.site.register(Category, TranslatedCategoryAdmin)
admin.site.register(Product, TranslatedProductAdmin)
admin.site.register(ProductOption, TranslatedOptionAdmin)
from mezzanine.conf import settings
from modeltranslation.translator import translator, TranslationOptions
applications = settings.INSTALLED_APPS
class TranslatedSlugged(TranslationOptions):
fields = ('title',)
class TranslatedDisplayable(TranslatedSlugged):
fields = ('_meta_title', 'description')
class TranslatedBasePage(TranslatedDisplayable):
fields = ('titles',)
class TranslatedRichText(TranslationOptions):
fields = ('content',)
if "mezzanine.pages" in applications:
from mezzanine.pages.models import RichTextPage, Page, Link
class TranslatedPage(TranslatedBasePage):
fields = ()
class TranslatedRichTextPage(TranslatedRichText):
fields = ()
class TranslatedLink(TranslationOptions):
fields = ()
translator.register(Page, TranslatedPage)
translator.register(RichTextPage, TranslatedRichTextPage)
translator.register(Link, TranslatedLink)
if "mezzanine.galleries" in applications:
from mezzanine.galleries.models import GalleryImage, Gallery
class TranslatedGallery(TranslatedRichText):
fields = ()
class TranslatedGalleryImage(TranslationOptions):
fields = ('description',)
translator.register(Gallery, TranslatedGallery)
translator.register(GalleryImage, TranslatedGalleryImage)
if "mezzanine.forms" in applications:
from mezzanine.forms.models import Form, Field
class TranslatedForm(TranslatedRichText):
fields = ('button_text', 'response', 'email_subject', 'email_message',)
class TranslatedField(TranslationOptions):
fields = ('label', 'choices', 'default', 'placeholder_text', 'help_text',)
translator.register(Form, TranslatedForm)
translator.register(Field, TranslatedField)
if "mezzanine.blog" in applications:
from mezzanine.blog.models import BlogCategory, BlogPost
class TranslatedBlogCategory(TranslatedSlugged):
fields = ()
class TranslatedBlogPost(TranslatedDisplayable, TranslatedRichText):
fields = ()
translator.register(BlogCategory, TranslatedBlogCategory)
translator.register(BlogPost, TranslatedBlogPost)
# mezzanine.boot, mezzanine.conf, mezzanine.generic, mezzanine.accounts
# and mezzanine.mobile does not need translated models
# what about mezzanine.twitter ?
if "cartridge.shop" in applications:
from cartridge.shop.models import Category, Product, ProductOption, ProductImage, ProductVariation
from cartridge.shop.fields import OptionField
class TranslatedProduct(TranslatedDisplayable, TranslatedRichText):
fields = ()
class TranslatedProductImage(TranslationOptions):
fields = ('description',)
class TranslatedProductOption(TranslationOptions):
fields = ('name',)
class TranslatedProductVariation(TranslationOptions):
fields = tuple(('option%s' % opt[0] for opt in settings.SHOP_OPTION_TYPE_CHOICES))
@classmethod
def no_translated_option_fields(cls):
"""
Returns each of the model fields that are dynamically created
from ``SHOP_OPTION_TYPE_CHOICES`` in
``ProductVariationMetaclass``. Excludes translation fields added
by ``TranslatedProductVariation``.
"""
all_fields = cls._meta.fields
all_codes = [code for code, _ in settings.LANGUAGES]
return [f for f in all_fields if isinstance(f, OptionField) and f.name.split('_')[-1] not in all_codes]
# Fix form creation for the admin
ProductVariation.option_fields = no_translated_option_fields
class TranslatedCategory(TranslatedRichText):
fields = ()
translator.register(Category, TranslatedCategory)
translator.register(Product, TranslatedProduct)
translator.register(ProductImage, TranslatedProductImage)
translator.register(ProductOption, TranslatedProductOption)
translator.register(ProductVariation, TranslatedProductVariation)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment