Last active
August 29, 2015 14:00
-
-
Save Kniyl/11249940 to your computer and use it in GitHub Desktop.
reusable django app to create django-modeltranslation fields into mezzanine models
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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