使用JSON的Django多语言文本字段

使用JSON的Django多语言文本字段,django,django-models,django-forms,multilingual,django-cms,Django,Django Models,Django Forms,Multilingual,Django Cms,我最近问了这个问题,但我没有找到不应该这样做的好理由,所以我创建了一个支持多语言文本的模型字段,自动返回当前语言中的文本。这基本上是以json格式将自定义语言对象存储到数据库的字段。代码如下: Github: Ussage: from django.db import models from multilingualfield import MLTextField, MLHTMLField class MyModel(models.Model): text = MLTextField(

我最近问了这个问题,但我没有找到不应该这样做的好理由,所以我创建了一个支持多语言文本的模型字段,自动返回当前语言中的文本。这基本上是以json格式将自定义语言对象存储到数据库的字段。代码如下:

Github:

Ussage:

from django.db import models
from multilingualfield import MLTextField, MLHTMLField

class MyModel(models.Model):
    text = MLTextField()
    html = MLHTMLField()
像普通文本字段一样使用它,翻译是自动基于系统语言(translation.get_language)

Forms.py

from django import forms
from django.utils import simplejson as json

from .widgets import MultilingualWidget, MultilingualHTMLWidget
from .language import LanguageText

class MultilingualTextFormField(forms.CharField):

    widget = MultilingualWidget

    def __init__(self, *args, **kwargs):
        kwargs['widget'] = MultilingualWidget
        super(MultilingualTextFormField, self).__init__(*args, **kwargs)

    def clean(self, value):
        """
        The default is to have a TextField, and we will decode the string
        that comes back from this. However, another use of this field is
        to store a list of values, and use these in a MultipleSelect
        widget. So, if we have an object that isn't a string, then for now
        we will assume that is where it has come from.
        """
        value = super(MultilingualTextFormField, self).clean(value)
        if not value:
            return value
        if isinstance(value, basestring):
            try:
                valuejson = json.loads(value)
                Lang = LanguageText()
                Lang.values = valuejson
                return Lang
            except ValueError:
                try:
                    Lang = LanguageText(value,language=None)
                    return Lang
                except:
                    raise forms.ValidationError(
                        'JSON decode error: %s' % (unicode(exc),)
                    )
        else:
            return value
Language.py中的Language对象

from __future__ import unicode_literals

from django.core.exceptions import ValidationError
from django.conf import settings
from django.db import models, DatabaseError, transaction
from django.utils.translation import ugettext_lazy as _, get_language

try:
    import json
except ImportError:
    from django.utils import simplejson as json

def get_base_language(lang):
    if '-' in lang:
        return lang.split('-')[0]
    return lang

def get_current_language(base=True):
    l = get_language()
    if base:
        return get_base_language(l)
    return l


class LanguageText(object):
    '''
        JSON text field blah blah blah
    '''
    values = {}
    default_language = None
    max_length = -1

    def __init__(self, value=None, language=None, default_language=None, max_length=-1):
        self.max_length = max_length
        self.default_language = default_language
        self.values = {}
        if value is not None:
            self.value(value,language)

    def __call__(self, value=None, language=None):
        self.value(value,language)
        return self

    def get_available_language(self):
        return self.values.keys()

    def get_current_language(self, base=False):
        return get_current_language(base)

    def remove_language(self, lang):
        try:
            return self.values.pop(lang)
        except:
            pass

    def has_language(self, lang):
        return self.values.has_key(lang)

    def get(self, language=None, fallback=True):
        if language is None:
            curr_lang = get_current_language(False)
        else:
            curr_lang = language
        curr_lang_base = get_current_language(True)
        if curr_lang in self.values:
            return self.values[curr_lang]
        if not fallback:
            return None
        if curr_lang_base in self.values:
            return self.values[curr_lang_base]
        if self.default_language in self.values:
            return self.values[self.default_language]
        try:
            first_lang = self.values.keys()[0]
            return self.values[first_lang]
        except:
            pass
        return None

    def value(self, value=None, language=None):
        if value is None:   #Get value
            return self.get(language)
        else: #Set value
            if language is None:
                language = get_current_language(False)
            if self.max_length != -1:
                value = value[:self.max_length]
            self.values[language] = value
            return None

    def __unicode__(self):
        return self.value()

    def __str__(self):
        return unicode(self.value()).encode('utf-8')

    def __repr__(self):
        return unicode(self.value()).encode('utf-8')
widgets.py

from django import forms
from django.utils import simplejson as json
from django.conf import settings
from .language import LanguageText
from django.template import loader, Context

class MultilingualWidget(forms.Textarea):

    def __init__(self, *args, **kwargs):
        forms.Widget.__init__(self, *args, **kwargs)

    def render(self, name, value, attrs=None):
        if value is None: #New create or edit none
            vjson = '{}'
            aLang = []
            Lang = '[]'
            Langs = json.dumps(dict(settings.LANGUAGES))
            t = loader.get_template('multilingualtextarea.html')
            c = Context({"data":value,"vjson":vjson,"lang":Lang,"langs":Langs,"langobjs":settings.LANGUAGES,"fieldname":name})
            return t.render(c)
        if isinstance(value, LanguageText):
            vjson = json.dumps(value.values)
            aLang = value.get_available_language()
            Lang = json.dumps(aLang)
            Langs = json.dumps(dict(settings.LANGUAGES))
            t = loader.get_template('multilingualtextarea.html')
            c = Context({"data":value,"vjson":vjson,"lang":Lang,"langs":Langs,"langobjs":settings.LANGUAGES,"fieldname":name})
            return t.render(c)
        return "Invalid data '%s'" % value
所以我想知道这是一个好方法吗?为什么我不能这样做?Plz帮助对我来说很好

唯一可能影响性能的是频繁的json编码/解码。。。然而,除非您在一台资源最少的服务器上面对成千上万的用户,否则这不会产生重大影响

您链接到的上一个问题包含一些注释,指出使用其他方法添加其他语言可能更容易。但最终,这是个人偏好和可维护性的混合。如果它符合您的项目目标,我看不出有任何理由不按照您编写的方式来做

证明您的实现是最好的几乎是不可能的。也就是说,除非您通过在生产服务器上创建一个不同的、基于非json的实现和基准来证明这一点。您会注意到,在常规机器上,差异非常小。然而,只有个别的数字才能提供实际的证据,并能帮助您决定它是否“优化”和“资源友好”足以满足项目的目的。我想它会满足你的需要。。。但那只是我的2美分

from __future__ import unicode_literals

from django.core.exceptions import ValidationError
from django.conf import settings
from django.db import models, DatabaseError, transaction
from django.utils.translation import ugettext_lazy as _, get_language

try:
    import json
except ImportError:
    from django.utils import simplejson as json

def get_base_language(lang):
    if '-' in lang:
        return lang.split('-')[0]
    return lang

def get_current_language(base=True):
    l = get_language()
    if base:
        return get_base_language(l)
    return l


class LanguageText(object):
    '''
        JSON text field blah blah blah
    '''
    values = {}
    default_language = None
    max_length = -1

    def __init__(self, value=None, language=None, default_language=None, max_length=-1):
        self.max_length = max_length
        self.default_language = default_language
        self.values = {}
        if value is not None:
            self.value(value,language)

    def __call__(self, value=None, language=None):
        self.value(value,language)
        return self

    def get_available_language(self):
        return self.values.keys()

    def get_current_language(self, base=False):
        return get_current_language(base)

    def remove_language(self, lang):
        try:
            return self.values.pop(lang)
        except:
            pass

    def has_language(self, lang):
        return self.values.has_key(lang)

    def get(self, language=None, fallback=True):
        if language is None:
            curr_lang = get_current_language(False)
        else:
            curr_lang = language
        curr_lang_base = get_current_language(True)
        if curr_lang in self.values:
            return self.values[curr_lang]
        if not fallback:
            return None
        if curr_lang_base in self.values:
            return self.values[curr_lang_base]
        if self.default_language in self.values:
            return self.values[self.default_language]
        try:
            first_lang = self.values.keys()[0]
            return self.values[first_lang]
        except:
            pass
        return None

    def value(self, value=None, language=None):
        if value is None:   #Get value
            return self.get(language)
        else: #Set value
            if language is None:
                language = get_current_language(False)
            if self.max_length != -1:
                value = value[:self.max_length]
            self.values[language] = value
            return None

    def __unicode__(self):
        return self.value()

    def __str__(self):
        return unicode(self.value()).encode('utf-8')

    def __repr__(self):
        return unicode(self.value()).encode('utf-8')
from django import forms
from django.utils import simplejson as json
from django.conf import settings
from .language import LanguageText
from django.template import loader, Context

class MultilingualWidget(forms.Textarea):

    def __init__(self, *args, **kwargs):
        forms.Widget.__init__(self, *args, **kwargs)

    def render(self, name, value, attrs=None):
        if value is None: #New create or edit none
            vjson = '{}'
            aLang = []
            Lang = '[]'
            Langs = json.dumps(dict(settings.LANGUAGES))
            t = loader.get_template('multilingualtextarea.html')
            c = Context({"data":value,"vjson":vjson,"lang":Lang,"langs":Langs,"langobjs":settings.LANGUAGES,"fieldname":name})
            return t.render(c)
        if isinstance(value, LanguageText):
            vjson = json.dumps(value.values)
            aLang = value.get_available_language()
            Lang = json.dumps(aLang)
            Langs = json.dumps(dict(settings.LANGUAGES))
            t = loader.get_template('multilingualtextarea.html')
            c = Context({"data":value,"vjson":vjson,"lang":Lang,"langs":Langs,"langobjs":settings.LANGUAGES,"fieldname":name})
            return t.render(c)
        return "Invalid data '%s'" % value